Java SQLite
最后修改日期:2024 年 7 月 15 日
在本文中,我们将展示如何在 Java 中使用 SQLite 进行数据库编程。
SQLite 是一种无服务器、自包含和嵌入式数据库引擎。 它是集成在应用程序中的一个库,允许它们直接与数据库文件交互。 SQLite 支持符合 ACID 的事务,并使用动态类型作为表。 它广泛应用于各种系统中,包括 Web 浏览器、操作系统和移动电话。
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.0.0</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-core</artifactId>
<version>3.45.2</version>
</dependency>
</dependencies>
在示例中,我们使用 sqlite-jdbc 和 jdbi3-core 项目。
SQLite 版本
在第一个例子中,我们打印 SQLite 数据库的版本。 我们使用 Java JDBC。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
void main() {
String query = "SELECT SQLITE_VERSION()";
try (Connection con = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query)) {
if (rs.next()) {
System.out.println(rs.getString(1));
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(getClass().getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
该程序打印 SQLite 数据库的版本。
String query = "SELECT SQLITE_VERSION()";
要获取数据库的版本,我们调用 SQLITE_VERSION 函数。
try (Connection con = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query)) {
...
}
我们获取与数据库的连接。 从连接对象,我们创建语句。 稍后,我们使用 executeQuery 执行查询。
if (rs.next()) {
System.out.println(rs.getString(1));
}
next 方法将光标从其当前位置向前移动一行。
System.out.println(rs.getString(1));
getString 方法检索此 ResultSet 对象的当前行中指定列的值作为 String。
$ java Main.java 3.46.0
在下一个例子中,我们使用 Jdbi。
import org.jdbi.v3.core.Jdbi;
void main() {
String jdbcUrl = "jdbc:sqlite:test.db";
Jdbi jdbi = Jdbi.create(jdbcUrl);
String res = jdbi.withHandle(handle -> handle.createQuery("SELECT SQLITE_VERSION()")
.mapTo(String.class)
.one());
System.out.println(res);
}
我们使用 withHandle 创建数据库的句柄。 然后我们使用 createQuery 创建一个查询,使用 mapTo 将结果映射到 String,并使用 one 获取值。
批处理
批处理是指作为单个单元一起提交和执行的一组 SQL 语句。 此功能提供了性能优势,并简化了某些数据库操作的代码。
在此示例中,我们使用 Jdbi。
import org.jdbi.v3.core.Jdbi;
void main() {
String jdbcUrl = "jdbc:sqlite:test.db";
Jdbi jdbi = Jdbi.create(jdbcUrl);
jdbi.withHandle(handle -> handle.createBatch()
.add("DROP TABLE IF EXISTS cars")
.add("CREATE TABLE cars(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, price INTEGER)")
.add("INSERT INTO cars(name, price) VALUES('Audi',52642)")
.add("INSERT INTO cars(name, price) VALUES('Mercedes',57127)")
.add("INSERT INTO cars(name, price) VALUES('Skoda',9000)")
.add("INSERT INTO cars(name, price) VALUES('Volvo',29000)")
.add("INSERT INTO cars(name, price) VALUES('Bentley',350000)")
.add("INSERT INTO cars(name, price) VALUES('Citroen',21000)")
.add("INSERT INTO cars(name, price) VALUES('Hummer',41400)")
.add("INSERT INTO cars(name, price) VALUES('Volkswagen',21600)")
.execute());
System.out.println("Table created and data inserted using JDBI batch.");
}
在 test.db 数据库中,我们创建一个新的 cars 表。 这些语句放在一个批处理中。
选择特定值
在下一个例子中,我们从一行中选择一个特定的单元格。 我们使用 Jdbi。
import org.jdbi.v3.core.Jdbi;
import java.util.Optional;
void main() {
String jdbcUrl = "jdbc:sqlite:test.db";
Jdbi jdbi = Jdbi.create(jdbcUrl);
int id = 3;
Optional<String> res = jdbi.withHandle(handle ->
handle.select("SELECT name FROM cars WHERE id = ?", id)
.mapTo(String.class)
.findOne());
res.ifPresentOrElse(System.out::println, () -> System.out.println("N/A"));
}
如果结果集中只有一行,则 findOne 方法返回该行。 如果没有返回任何行,或者该行本身为空,则返回 Optional.empty。
$ java Main.java Skoda
检索行
在下一个例子中,我们检索表中的所有行。 我们使用 JDBC。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
void main() {
String query = "SELECT * FROM cars";
try (Connection con = DriverManager.getConnection("jdbc:sqlite:test.db");
PreparedStatement pst = con.prepareStatement(query);
ResultSet rs = pst.executeQuery()) {
while (rs.next()) {
System.out.printf("%d %s %d%n", rs.getInt(1),
rs.getString(2), rs.getInt(3));
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(getClass().getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
我们执行 SELECT * FROM cars 查询。
while (rs.next()) {
System.out.printf("%d %s %d%n", rs.getInt(1),
rs.getString(2), rs.getInt(3));
}
我们循环遍历结果集并打印所有行。
$ java Main.java 1 Audi 52642 2 Mercedes 57127 3 Skoda 9000 4 Volvo 29000 5 Bentley 350000 6 Citroen 21000 7 Hummer 41400 8 Volkswagen 21600
在下一个例子中,我们使用 Jdbi 检索所有行。
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.mapper.reflect.ConstructorMapper;
import java.util.List;
void main() {
String jdbcUrl = "jdbc:sqlite:test.db";
Jdbi jdbi = Jdbi.create(jdbcUrl);
List<Car> cars = jdbi.withHandle(handle ->
handle.select("SELECT * FROM cars")
.registerRowMapper(Car.class, ConstructorMapper.of(Car.class))
.mapTo(Car.class)
.list());
if (cars.isEmpty()) {
System.out.println("No cars found.");
} else {
System.out.println("List of cars:");
cars.forEach(System.out::println);
}
}
public record Car(int id, String name, int price) {
}
该示例使用行映射器自动将每一行映射到 Car 记录。
预处理语句
当我们编写预处理语句时,我们使用占位符,而不是直接将值写入语句中。 预处理语句提高了安全性和性能。
PreparedStatement 是一个对象,它表示 JDBC 中预编译的 SQL 语句。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
void main() {
int carPrice = 23999;
String carName = "Oldsmobile";
String sql = "INSERT INTO cars(name, price) VALUES(?, ?)";
try (Connection con = DriverManager.getConnection("jdbc:sqlite:test.db")) {
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, carName);
pst.setInt(2, carPrice);
pst.executeUpdate();
System.out.println("A new car has been inserted");
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(getClass().getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
该示例将新行插入到表中。
String sql = "INSERT INTO cars(name, price) VALUES(?, ?)";
当我们编写预处理语句时,我们使用占位符,而不是直接将值写入语句中。 预处理语句速度更快,并且可以防止 SQL 注入攻击。 ? 是一个占位符,稍后将被填充。
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, carName);
pst.setInt(2, carPrice);
pst.executeUpdate();
System.out.println("A new car has been inserted");
}
我们使用 prepareStatement 创建一个 PreparedStatement,并将值传递给占位符。 然后我们使用 executeUpdate 执行语句。
在 Jdbi 中,我们使用 bind 方法。
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.mapper.reflect.ConstructorMapper;
import java.util.Optional;
void main() {
String jdbcUrl = "jdbc:sqlite:test.db";
Jdbi jdbi = Jdbi.create(jdbcUrl);
int id = 3;
Optional<Car> res = jdbi.withHandle(handle ->
handle.select("SELECT * FROM cars WHERE id = ?")
.registerRowMapper(Car.class, ConstructorMapper.of(Car.class))
.bind(0, id)
.mapTo(Car.class)
.findOne());
res.ifPresentOrElse(System.out::println, () -> System.out.println("N/A"));
}
public record Car(int id, String name, int price) {
}
该示例选择特定行并将其映射到 Car 记录中。 将值绑定到占位符是使用 bind 完成的。
$ java Main.java Car[id=3, name=Skoda, price=9000]
来源
在本文中,我们展示了如何在 Java 中拆分字符串。
作者
列出所有Java教程。