Apache Commons DbuTils 详解
The Apache Commons DbUtils package is a set of Java utility classes for easing JDBC development.
Dbutils是Apache组开发出来的一组用于简化 JDBC 开发的 Java 实用程序类。通过封装来简化增删改查等操作,实际上比起Mysql提供的jar包,简化了很多封装的步骤,我们只需要创建Bean类,Dbutils就会返回封装好的类。这在开发中会减少很多不必要的代码。
Maven中央仓库:
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.8</version>
</dependency>
将上述代码添加到Maven配置文件中,就可以使用Maven搜索依赖项来获得。
连接池
我们在没有接触连接池时,通常都是通过驱动、数据库url、账户密码“四件套”来得到数据库连接对象Connection;
//创建驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC","root","root");
在通常学习的过程中只是用完即关,那么问题就来了,数据库的连接过程消耗的时间和资源是较大的,如果多次请求同一个连接,那么造成的不必要的性能消耗是比较大的,为了优化这一开销,于是连接池出现了,连接池能够管理多个数据库连接,可以减少创建和关闭数据库连接的消耗。这是“空间换时间
”的经典案例。上述的代码Connection对象是由DriverManager创建的,DriverManager是java早期版本用来调用数据库驱动的工具包。
数据源
数据源是指数据库应用程序所使用的数据库或者数据库服务器。在数据源中存储了所有建立数据库连接的信息
。比较常见的数据源有:DBCP,C3P0,ODBC.
这些数据源是将连接数据库所需要的信息进行约束,并以特定的规范进行提取,通过配置文件中的参数,来降低代码的耦合。
DataSource
随着JDBC版本的迭代,sun公司推出了DataSource。
public interface DataSource extends CommonDataSource, Wrapper
DataSource提供到此 DataSource
对象所表示的物理数据源的连接。作为 DriverManager
工具的替代项,DataSource
对象是获取连接的首选方法。
DataSource
接口由驱动程序供应商实现。共有三种类型的实现:
- 基本实现 - 生成标准的
Connection
对象 - 连接池实现 - 生成自动参与连接池的
Connection
对象。此实现与中间层连接池管理器一起使用。 - 分布式事务实现 - 生成一个
Connection
对象,该对象可用于分布式事务,大多数情况下总是参与连接池。此实现与中间层事务管理器一起使用,大多数情况下总是与连接池管理器一起使用。
当我们接触了DataSource后,我们就可以十分便捷的使用数据源来创建数据库连接:
- 通过读取DBCP数据的配置文件dbcp-config.properties,来创建数据库连接;
FileInputStream ros = new FileInputStream("src/dbcp-config.properties");
Properties ps = new Properties();
ps.load(ros);
DataSource dataSource = BasicDataSourceFactory.createDataSource(ps);
Connection conn = dataSource.getConnection();
- 通过C3P0来创建数据库连接:
DataSource ds = new ComboPooledDataSource();
Connection conn = ds.getConnection();
注意:使用C3P0来创建数据库连接会在项目src目录下寻找c3p0-config.xml
文件。语句的后半段new ComboPooledDataSource()
可以传入参数指定named-config
的配置项,来创建不同的连接。
上述的两种数据源都是实现连接池的。
QueryRunner类
QueryRunner是apache提供的dbutils的核心类,定义为:
public class QueryRunner
extends AbstractQueryRunner
Executes SQL queries with pluggable strategies for handling s. This class is thread safe.
ResultSet
使用用于处理 的可插入策略执行 SQL 查询。此类是线程安全的。结果集。
笔者下载的dbutils的jar版本较低,只有四种构造方法,而在apache的官方文档中拥有七种构造方法,但是我们常用的构造方法是:
public QueryRunner(DataSource ds) {
super(ds);
}
当我们传入一个DataSource对象时,QueryRunner父类AbstractQueryRunner的构造方法。
protected final DataSource ds;
....
public AbstractQueryRunner(DataSource ds) {
this.ds = ds;
}
将参数赋值给类中的ds,在之后执行sql语句时,会直接调用ds创建连接。
查询的一般过程与query方法
我们进行查询时一般会写好sql语句,然后调用query方法来传递不同的 参数来查询不同的结果。
DataSource ds = new ComboPooledDataSource();
QueryRunner qr = new QueryRunner(ds);
String sql = "select * from product2";
List<Object[]> list= qr.query(sql,new ArrayListHandler());
for (Object[] os:list
) {
String s = Arrays.toString(os);
System.out.println(s);
}
我们首先创建DataSourse对象ds,通过QueryRunner的构造方法传入ds来获得QueryRunner对象qr,之后我们编写好sql语句,调用query方法并返回结果。
以上就是使用QueryRunner来查询的过程,之后我们进入query的内部来看看:
public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
Connection conn = this.prepareConnection();
return this.query(conn, true, sql, rsh, (Object[])null);
}
query方法重载的方法很多,但是参数大多都大同小异:
-
sql:编写好的sql语句,也可以使用“?”占位符,然后使用Object[]数组传递参数,避免sql注入。
-
rsh:ResultSetHandler接口的实现类都可以将结果集转换为泛型类T.
public interface ResultSetHandler<T>
-
Object[] param:替换sql中的占位符“?”,来达到返回不同列,不同条件的结果集的目的。
QueryRunner qr = new QueryRunner(dataSource);
String sql = "select * from product2 where category_id=?";
Object[] os = {"c001"};
List<Product2> list = qr.query(sql, new BeanListHandler<Product2>(Product2.class),os);
for (Product2 p:list
) {
System.out.println(p);
}
如上就可以通过parm来查询到category_id=‘c001’的信息。
让我们更深入quary方法:
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
Connection conn = this.prepareConnection();
return this.query(conn, true, sql, rsh, params);
}
在方法的第一行,**我们通过调用本方法的prepareConnection方法来获得Connection对象,第二行返回调用重载方法的结果。**在方法prepareConnection中:
protected Connection prepareConnection() throws SQLException {
if (this.getDataSource() == null) {
throw new SQLException("QueryRunner requires a DataSource to be invoked in this way, or a Connection should be passed in");
} else {
return this.getDataSource().getConnection();
}
}
首先先进行判断,DataSourse属性是否为null,然后调用javax.sql.Connection的getConnection方法返回Connection对象,所以当我们传入DataSourse对象后,会自动从连接池中获取连接对象。
ResultSetHandler接口实现类
Implementations of this interface convert ResultSets into other objects.
- ResultSetHandler实现类:AbstractKeyedHandler, AbstractListHandler, ArrayHandler, ArrayListHandler, BaseResultSetHandler, BeanHandler, BeanListHandler, BeanMapHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler, ScalarHandler
ResultSetHandler接口实现类是将结果集转换为泛型类,而调用不同的实现类可以返回不同的结果。
-
使用BeanListHandler获取封装后的Bean类:
@Test public void select_all() throws Exception { FileInputStream ros = new FileInputStream("src/dbcp-config.properties"); Properties ps = new Properties(); ps.load(ros); DataSource dataSource = BasicDataSourceFactory.createDataSource(ps); QueryRunner qr = new QueryRunner(dataSource); String sql = "select * from product2 where category_id=?"; Object[] os = {"c001"}; List<Product2> list = qr.query(sql, new BeanListHandler<Product2>(Product2.class),os); for (Product2 p:list ) { System.out.println(p); } }
-
使用ArrayListHandler获取List<Object[]>
@Test public void listselectall() throws SQLException { DataSource ds = new ComboPooledDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from product2"; List<Object[]> list= qr.query(sql,new ArrayListHandler()); for (Object[] os:list ) { String s = Arrays.toString(os); System.out.println(s); } }
-
使用KeyedHandler获取Map<Object, Map<String, Object>>类型数据:
@Test public void keyedselectall() throws SQLException { DataSource ds = new ComboPooledDataSource(); QueryRunner qs = new QueryRunner(ds); String sql = "select * from product2"; Map<Object, Map<String, Object>> map = qs.query(sql, new KeyedHandler<>()); Set<Object> set = map.keySet(); for (Object s:set ) { System.out.println(s+" "+map.get(s)); } }
注意:使用此类返回的嵌套的map集合,外层返回的key值为Integar型,使用Set集合获取keySet返回值是,注意泛型的类型。
-
使用ColumnListHandler获取某一列的全部值
@Test public void columnlistall() throws SQLException { DataSource ds = new ComboPooledDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from product2"; List<Object> column = qr.query(sql,new ColumnListHandler<>("pname")); System.out.println(column); }
以上只展现一部分的实现类的实例,这些也是最常用的实现类,关于更多的实现类的问题可以参考Apache的官方文档:
ResultSetHandler (Apache Commons DbUtils 1.7 API)
笔者操作的表:
create table product(
pid int primary key,
pname varchar(20),
price double,
category_id varchar(32)
);
INSERT INTO product(pid,pname,price,category_id) VALUES(1,'IBM',5500,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(2,'长城',3200,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(3,'惠普',5000,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(4,'华为',3800,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(5,'小米',2000,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(6,'OPPO',3400,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(7,'NOKIA',2000,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(8,'佰草集',800,'c003');
INSERT INTO product(pid,pname,price,category_id) VALUES(9,'玉兰油',200,'c003');
INSERT INTO product(pid,pname,price,category_id) VALUES(10,'大宝',5,'c003');
以上就是全部的文章啦,觉得不错的话,点个赞吧!