Apache Commons DbuTils 详解

Apache Commons DbUtils 是一组简化 JDBC 开发的 Java 工具类。本文详细介绍了如何使用 Connection Pool、DataSource、QueryRunner 类以及 ResultSetHandler 接口,帮助开发者更高效地执行数据库查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 接口由驱动程序供应商实现。共有三种类型的实现:

  1. 基本实现 - 生成标准的 Connection 对象
  2. 连接池实现 - 生成自动参与连接池的 Connection 对象。此实现与中间层连接池管理器一起使用。
  3. 分布式事务实现 - 生成一个 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接口实现类是将结果集转换为泛型类,而调用不同的实现类可以返回不同的结果。

  • 使用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');

以上就是全部的文章啦,觉得不错的话,点个赞吧!

commons-dbutils包是Apache开源组织提供的用于操作数据库的工具包。简单来讲,这个工具包就是用来更加方便我们操作数据库的,最近工作中使用了一下,感觉确实方便很多,基本告别自己封装JDBC代码对数据库进行增删改查了。代码看着也很简洁。 例如: 增删改查使用的类:QueryRunner类+ResultSetHandler类,使用这俩类就可以解决掉。 QueryRunner类的query()方法:new QueryRunner().query(Connection conn, String sql, ResultSetHandler rsh) query方法后面参数中加一个Connection连接,是在获取不到数据源的情况下,也就是说,QueryRunner的实例化构造函数使用无参的那个,下面我的实现代码就是用的这种方法。 当然还有一种实例化:new QueryRunner(new Datasource()).query(String sql, ResultSetHandler rsh) query方法中的参数 ResultSetHandler 参数中加上ResultSetHandler接口的实现类参数(下面这些实现类),执行完SQL后,返回的数据就是已经封装好的我们想要的结果了。 ArrayHandler :将ResultSet中第一行的数据转化成对象数组 ArrayListHandler将ResultSet中所有的数据转化成List,List中存放的是Object[] BeanHandler :将ResultSet中第一行的数据转化成Bean对象 BeanListHandler :将ResultSet中所有的数据转化成List ColumnListHandler :将ResultSet中某一列的数据存成List KeyedHandler :将ResultSet中存成映射,key为某一列对应为Map,Map中存放的是数据 MapHandler :将ResultSet中第一行的数据存成Map MapListHandler :将ResultSet中所有的数据存成List<Map> ScalarHandler :将ResultSet中一条记录的其中某一列的数据存成Object
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值