Apache 数据库工具 commons-dbutils 的使用
Jar 引入
官网:http://commons.apache.org/proper/commons-dbutils/
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
Jar 介绍
Apache Commons DbUtils 库是一个相当小的一组类,它们被设计用来在没有资源泄漏的情况下简化 JDBC 调用处理,并且具有更简洁的代码。
由于 JDBC 资源清理非常繁琐且容易出错,因此 DBUtils 类有助于抽取出重复代码,以便开发人员只专注于与数据库相关的操作。
使用优点
- 无资源泄漏 - DBUtils 类确保不会发生资源泄漏。
- 清理和清除代码 - DBUtils 类提供干净清晰的代码来执行数据库操作,而无需编写任何清理或资源泄漏防护代码。
- Bean 映射 - DBUtils 类支持从结果集中自动填充 javabeans。
设计原则
- 小 - DBUtils 库的体积很小,只有较少的类,因此易于理解和使用。
- 透明 - DBUtils 库在后台没有做太多工作,它只需查询并执行。
- 快速 - DBUtils 库类不会创建许多背景对象,并且在数据库操作执行中速度非常快。
连接测试
示例代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class MainApp {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
static final String USER = "user";
static final String PASS = "password";
public static void main(String[] args) throws SQLException {
Connection conn = null;
QueryRunner queryRunner = new QueryRunner();
conn = DriverManager.getConnection(DB_URL, USER, PASS);
ResultSetHandler<Employee> resultHandler = new BeanHandler<Employee>(Employee.class);
try {
Employee emp = queryRunner.query(conn, "SELECT * FROM employees WHERE first=?", resultHandler, "Sumit");
// Display values
System.out.print("ID: " + emp.getId() + ", Age: " + emp.getAge() + ", First: " + emp.getFirst() + ", Last: " + emp.getLast());
} finally {
DbUtils.close(conn);
}
}
}
异常处理
异常一:连接报错:
Exception in thread "main" java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
解决:在连接字符串后面加上 ?serverTimezone=UTC,其中 UTC 是统一标准世界时间。如下所示:
static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
异常二:若使用驱动 com.mysql.jdbc.Driver ,则虽然程序正常运行,但提示:
Loading class
com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
解决:解决方案有两种:
切换驱动
com.mysql.jdbc.Driver为com.mysql.cj.jdbc.Driver。删除驱动连接。
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; DbUtils.loadDriver(JDBC_DRIVER);此时,通过 SPI 自动注册驱动程序,不需要手动加载驱动程序类。
数据操作
新增数据
String insertQuery ="INSERT INTO employees(id,age,first,last) VALUES (?,?,?,?)";
int insertedRecords = queryRunner.update(conn, insertQuery, 104, 30, "Sohan","Kumar");
读取数据
ResultSetHandler<Employee> resultHandler = new BeanHandler<Employee>(Employee.class);
Employee emp = queryRunner.query(conn, "SELECT * FROM employees WHERE first=?", resultHandler, "Sumit");
其中,
- resultHandler −
ResultSetHandler对象将结果集映射到Employee对象。 - queryRunner −
QueryRunner对象在数据库中插入Employee对象。
更新数据
String updateQuery = "UPDATE employees SET age=? WHERE id=?";
int updatedRecords = queryRunner.update(conn, updateQuery, 33, 104);
其中,
- updateQuery − 更新包含占位符的查询。
- queryRunner − QueryRunner 对象更新数据库中的员工对象。
删除数据
String deleteQuery = "DELETE FROM employees WHERE id=?";
int deletedRecords = queryRunner.delete(conn, deleteQuery, 33,104);
Java
其中,
- deleteQuery − 删除包含占位符的查询。
- queryRunner −
QueryRunner对象删除数据库中的员工对象。
DBUtils 核心类
QueryRunner
org.apache.commons.dbutils.QueryRunner 类是 DBUtils 库中的中心类。
它执行带有可插入策略的 SQL 查询来处理 ResultSets。 这个类是线程安全的。
AsyncQueryRunner
org.apache.commons.dbutils.AsyncQueryRunner 类有助于执行具有异步支持的长时间运行的 SQL 查询。 这个类是线程安全的。
该类支持与 QueryRunner 相同的方法,但它返回 Callable 对象,在之后可以使用它来检索结果。
ResultSetHandler
org.apache.commons.dbutils.ResultSetHandler 接口负责将 ResultSets 转换为对象。
BeanHandler
org.apache.commons.dbutils.BeanHandler 是 ResultSetHandler 接口的实现,负责将第一个 ResultSet 行转换为 JavaBean。 这个类是线程安全的。
BeanListHandler
org.apache.commons.dbutils.BeanListHandler 是 ResultSetHandler 接口的实现,负责将 ResultSet 行转换为 Java Bean 列表。 这个类是线程安全的。
ArrayListHandler
org.apache.commons.dbutils.ArrayListHandler 是 ResultSetHandler 接口的实现,负责将 ResultSet 行转换为 object[]。 这个类是线程安全的。
MapListHandler
org.apache.commons.dbutils.MapListHandler 是 ResultSetHandler 接口的实现,负责将 ResultSet 行转换为 Maps 列表。 这个类是线程安全的。
自定义 DBUtils
自定义处理程序
可以通过实现 ResultSetHandler 接口或扩展任何现有的 ResultSetHandler 实现来创建自己的自定义处理程序。
在下面的示例中,我们通过扩展 BeanHandler 类创建了自定义处理程序 EmployeeHandler。
EmployeeHandler.java
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class EmployeeHandler extends BeanHandler<Employee> {
public EmployeeHandler() {
super(Employee.class);
}
@Override
public Employee handle(ResultSet rs) throws SQLException {
Employee employee = super.handle(rs);
employee.setName(employee.getFirst() + ", " + employee.getLast());
return employee;
}
}
MyHandlerMain.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
public class MyHandlerMain {
static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
static final String USER = "user";
static final String PASS = "password";
public static void main(String[] args) throws SQLException {
Connection conn = null;
QueryRunner queryRunner = new QueryRunner();
conn = DriverManager.getConnection(DB_URL, USER, PASS);
EmployeeHandler employeeHandler = new EmployeeHandler();
try {
Employee emp = queryRunner.query(conn, "SELECT * FROM employees WHERE first=?", employeeHandler, "Sumit");
System.out.print("ID: " + emp.getId() + ", Age: " + emp.getAge() + ", Name: " + emp.getName());
} finally {
DbUtils.close(conn);
}
}
}
自定义行处理器
如果数据库表中的列名和等价的 javabean 对象名称不相似,那么我们可以通过使用自定义的 BasicRowProcessor 对象来映射它们。
EmployeeHandler2.java
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.BeanProcessor;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class EmployeeHandler2 extends BeanHandler<Employee> {
public EmployeeHandler2() {
super(Employee.class, new BasicRowProcessor(new BeanProcessor(mapColumnsToFields())));
}
@Override
public Employee handle(ResultSet rs) throws SQLException {
Employee employee = super.handle(rs);
employee.setName(employee.getFirst() +", " + employee.getLast());
return employee;
}
public static Map<String, String> mapColumnsToFields() {
Map<String, String> columnsToFieldsMap = new HashMap<>();
columnsToFieldsMap.put("ID", "id");
columnsToFieldsMap.put("AGE", "age");
return columnsToFieldsMap;
}
}
MyHandlerMain2.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
public class MyHandlerMain2 {
static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
static final String USER = "user";
static final String PASS = "password";
public static void main(String[] args) throws SQLException {
Connection conn = null;
QueryRunner queryRunner = new QueryRunner();
conn = DriverManager.getConnection(DB_URL, USER, PASS);
EmployeeHandler employeeHandler = new EmployeeHandler();
try {
Employee emp = queryRunner.query(conn, "SELECT * FROM employees WHERE first=?", employeeHandler, "Sumit");
System.out.print("ID: " + emp.getId() + ", Name: " + emp.getName());
} finally {
DbUtils.close(conn);
}
}
}
使用 DataSource
以下示例将演示如何在 QueryRunner 和数据源的帮助下使用查询读取记录。
语法
QueryRunner queryRunner = new QueryRunner( dataSource );
Employee emp = queryRunner.query("SELECT * FROM employees WHERE first=?", resultHandler, "Sumit");
其中,
dataSource- 配置了DataSource对象。resultHandler-ResultSetHandler对象将结果集映射到Employee对象。queryRunner- 用于从数据库读取Employee对象的QueryRunner对象。
需要引入 Jar 包:
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
CustomDataSource.java:
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
public class CustomDataSource {
static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
static final String USER = "user";
static final String PASS = "password";
private static final BasicDataSource basicDataSource;
static {
basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName(JDBC_DRIVER);
basicDataSource.setUsername(USER);
basicDataSource.setPassword(PASS);
basicDataSource.setUrl(DB_URL);
}
public static DataSource getInstance() {
return basicDataSource;
}
}
MyHandlerMain3.java
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class MyHandlerMain3 {
public static void main(String[] args) throws SQLException {
QueryRunner queryRunner = new QueryRunner(CustomDataSource.getInstance());
ResultSetHandler<Employee> resultHandler = new BeanHandler<Employee>(Employee.class);
Employee emp = queryRunner.query("SELECT * FROM employees WHERE id=?", resultHandler, 103);
System.out.print("ID: " + emp.getId() + ", Age: " + emp.getAge() + ", First: " + emp.getFirst() + ", Last: " + emp.getLast());
}
}
参考资料
- https://www.yiibai.com/dbutils