本篇将会详细地介绍Apache公司的JDBC帮助工具类DbUtils以及如何使用。在上一篇中我们已经通过将以前对dao层使用JDBC操作数据库的冗余代码进行了简易封装形成自己的简单工具类JdbcUtils,而在这过程中很多都是借鉴和参考了DbUtils的代码,因此通过上一篇的学习,会让我们在对DbUtils进行更快速简单的认识。

  俗话说学习一个开源的工具最好的方法就是看其官方文档,是的,在Apache官网中对DbUtils进行了详细的介绍:http://commons.apache.org/proper/commons-dbutils/ 。(或者下载了DbUtils的jar中也有相应文档)

  DbUtils是一些类组成的用于简化JDBC开发的库,解决我们以前根据“模板”代码写出的大部分的冗余部分,将我们的代码进行最大程度的简化,使我们只关心于查询和更新(包括添加、修改和删除)数据。就好像上一篇博客中我们重点写的query和update方法。

  DbUtils能做些什么?虽然JDBC代码不难,但是根据我们以前所写的“模板”代码费时又费力,非常容易丢失链接并且难以追寻,而使用DbUtils基本不会发生资源泄露(比如链接的丢失)。当然和上一篇博文相同,DbUtils也提供了一个对结果集处理的接口ResultSetHandler,我们可以实现这个接口来对结果集进行处理,也可以使用DbUtils提供的实现类,例如BeanHandler或者BeanListHandler等等,有很多实用的结果集处理器类。如果有一些公司不使用hibernate的话一般会选用DbUtils。

  DbUtils最主要的就两个,QueryRunner类和ResultSetHandler接口。

  QueryRunner类这个类主要用于提供各种重载形式的batch方法、query方法和update 方法,其中update 方法包含添加、删除和修改。

  QueryRunner并不算一个静态工具类,因此我们要使用必须先创建一个QueryRunner类的对象,而这就有两种构造器,分别是无参的和有参的,其中有参的构造器接收一个连接池对象DataSource。

  

  

  可以从手册中看到,如果在创建QueryRunner对象时给定了一个连接池对象,那么在一些不需要Connection对象为参数的方法被调用时会从连接池中自动获取连接,调用完后会将连接重新返回到连接池中;而对于无参的构造器来说,在调用方法时必须指定Connection对象,同时调用完方法后Connection对象的处理要自己负责。

  下面就看看对于无参和有参的QueryRunner对象的各种重载形式的query方法和update方法:

  

  

  可以看到这些方法中主要就分为两种,一种是有Connection对象参数的,一种是无Connection对象参数的。上面已经说过了,无Connection对象参数的方法是从有参QueryRunner的连接池中获取链接,同时会自动将连接返还给连接池。而有Connection参数的方法由调用者负责关闭连接,这种方法看似麻烦,但是由多条SQL组成的事务进行整体执行却是必须的,因为我们不需要只执行一条SQL就还给连接池。

  除了query方法和update方法,QueryRunner类还有一个batch方法,用于执行SQL批处理:

  

  这个方法用于对某一条SQL执行多次,而我们提供给这个方法的参数中是一个二维数组,那么怎么用呢?

  比如“insert into user(id,name,age) values(?,?,?)”这样的SQL语句,batch方法中的二维数组参数就可以是 [ [1,”Ding”,25],[2,”LRR”,24] ] 这样的形式,也就是批处理执行两次,而每次的参数都不同。

  上面的介绍基本就是QueryRunner的全部,当然QueryRunner只是DbUtils的一部分,而另一部分在于QueryRunner中query方法参数中的ResultSetHandler接口,用于处理结果集,这一点上一篇博客已经讲述的很清楚了。而在DbUtils中为我们已经写好了更多的这个接口的实现类:

  

  除了我们上一篇博客自己动手实现的BeanHandler和BeanListHandler之外,在DbUtils中可以使用便捷的结果集处理器还有

  ArrayHandler:把结果集中的第一行数据封装进对象数组中。

  ArrayListHandler:把结果集中的每一行数据封装进数组,再将这些数组存进List集合中。

  ColumnListHandler:将结果集中的某一列所有的数据存进List集合中。

  KeyedHandler:将结果集中的每一行数据封装进一个Map中,再把这些Map存到一个Map里,其Key为指定的Key。

  MapHandler:将结果集中的第一行数据封装进Map里,Key为列名,value就是对应的值。

  MapListHandler:将结果集中的每一行数据封装到Map中,再将这些Map存放进List中。

  记得上一篇博客中我们在JDBC工具类JdbcUtils中重点创建的自定义的update方法和query方法吗(上一篇博客的第四点和第五点),那只是为了我们将冗余代码进行封装,而在本篇中我们可以在JdbcUtils中删了这里两个方法,而直接在dao层中使用DbUtils进行低层的增删改查。

例1

  那么在下面的代码中就对上一篇博客最后的UserDao中的增删改查进行重构:

 public class UserDao {
// 添加用户
public void add(User user) throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "insert into user(id,name,age) values(?,?,?)";
Object[] params = { user.getId(), user.getName(), user.getAge() };
qr.update(sql, params);
} // 删除用户
public void delete(int id) throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "delete from user where id=?";
Object params = id;
qr.update(sql, params);
} // 修改用户
public void update(User user) throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "update user set name=?,age=? where id=?";
Object[] params = { user.getName(), user.getAge(), user.getId() };
qr.update(sql, params);
} // 查找某个用户
public User find(int id) throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select * from user where id=?";
Object params = id;
User user = qr.query(sql, new BeanHandler<>(User.class), params);
return user;
} // 列出所有用户
public List<User> getAllUser() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select * from user";
List<User> list = qr.query(sql, new BeanListHandler<>(User.class));
return list;
}
}

  可以看到使用QueryRunner就将我们的增删改查语句变得非常简单,同时我们在工具类JdbcUtils中也不用另外再写update方法和query方法,在JdbcUtils中主要是创建连接池。由于我们在创建QueryRunner对象时使用了DataSource作为参数,这样我们在使用无Connection对象的update方法和query方法都可以不用指定连接,同时这些方法会将我们的连接自动放回连接池,因此我们在JdbcUtils甚至都可以不用写释放资源的代码(当然具体情况具体分析)。 

例2

  再补充一个使用DbUtils的批处理batch方法的demo:

public void batchInsertTest() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "insert into user(id,name,age) values(?,?,?)";
Object[][] params = new Object[5][3];
for(int i=0;i<params.length;i++) {
params[i] = new Object[]{i+1,"aa"+i,25+i};
}
qr.batch(sql, params);
}

结果如下:

 

  关于DbUtils中的QueryRunner类就差不多介绍完了,主要就是batch、query和update 方法。

  而对于结果集处理器类,DbUtils给我们提供了很多针对ResultSetHandler接口的实现类,如果这些实现类都不能满足我们的需要,我们也可以实现ResultSetHandler接口来制作我们所需要功能的实现类。

例3

  下面使用DbUtils中的结果集处理器类之一的ArrayHandler类来简单演示下demo(以上面批处理batch方法调用后的数据库中数据为例):

 public void arrayHandlerTest() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select * from user";
Object[] firstUser = qr.query(sql, new ArrayHandler());
for(Object o:firstUser) {
System.out.println(o);
}
}

  ArrayHandler类只将结果集的第一行数据封装进一个对象数组中,在控制台观察:

  

例4:

  有时候我们需要计算一张表中的总记录数,例如在使用数据库进行分页的时候就需要知道有多少数据,那么将查询结果以结果集返回也可以使用ArrayHandler简单处理,因为数组的第一个元素就是查询结果,但下面的代码看似没有问题,却在运行时会抛出异常:

 public void countTest() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select count(*) from user";
Object[] result = qr.query(sql, new ArrayHandler());
int count = (int) result[0];
System.out.println(count);
}

异常原因:

  

  也就是说在MySQL中以count方法在JDBC中是以Long类型返回查询的数值,因此我们不能只用Integer类型。这点要注意,但是总记录数不大时可以将Long类型强制转换为Integer类型:

 public void countTest() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select count(*) from user";
Object[] result = qr.query(sql, new ArrayHandler());
int count = ((Long)result[0]).intValue();
System.out.println(count);
}

  当然还有其他的很实用的结果集处理器类,这里就不一一介绍了。本篇对DbUtils的讲解就结束了,对于DbUtils的使用是很简单的,只要掌握了QueryRunner类和ResultSetHandler接口及其实现类,就能很好的掌握DbUtils。

开源JDBC工具类DbUtils的更多相关文章

  1. JDBC工具类-DButils(QueryRunner-ResultSetHandler)

    简述: DBUtils是Java编程中的数据库操作实用工具,小巧简单实用. DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码. DBUtils三个核心功能: QUeryRunne ...

  2. Apache—dbutils开源JDBC工具类库简介

    Apache—dbutils开源JDBC工具类库简介 一.前言 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用 ...

  3. 自己实现的JDBC工具类

    最近做了个后台应用程序,刚开始用Spring+iBatis来做的,后来因为种种原因,不让用Spring.iBatis以及一些开源的工具包.   于是用JDBC重写了原来的Service实现,项目做完了 ...

  4. MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  5. MySQL数据库学习笔记(十)----JDBC事务处理、封装JDBC工具类

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  6. MySQL JDBC事务处理、封装JDBC工具类

    MySQL数据库学习笔记(十)----JDBC事务处理.封装JDBC工具类 一.JDBC事务处理: 我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败.在MySQL中提供了Commit. ...

  7. DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

    DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...

  8. JDBC_14_使用JDBC工具类实现模糊查询

    使用JDBC工具类实现模糊查询 代码: import java.sql.*; /** * 模糊查询 * 测试DBUtils */ public class JDBCTest09 { public st ...

  9. jdbc 11: 封装自己的jdbc工具类

    jdbc连接mysql,封装自己的jdbc工具类 package com.examples.jdbc.utils; import java.sql.*; import java.util.Resour ...

随机推荐

  1. uva--11991 - Easy Problem from Rujia Liu?(sort+二分 map+vector vector)

    11991 - Easy Problem from Rujia Liu? Though Rujia Liu usually sets hard problems for contests (for e ...

  2. BestCoder Round #50 (div.1) 1003 The mook jong (HDU OJ 5366) 规律递推

    题目:Click here 题意:bestcoder 上面有中文题目 分析:令f[i]为最后一个木人桩摆放在i位置的方案,令s[i]为f[i]的前缀和.很容易就能想到f[i]=s[i-3]+1,s[i ...

  3. VIM: 解决vi/vim中粘贴时行首出现很多缩进和空格的问题

    解决vi/vim中粘贴时行首出现很多缩进和空格的问题 http://www.jbxue.com/LINUXjishu/12232.html 由于在secureCRT中会将原来的文本原封不动的按照字符串 ...

  4. [Swust OJ 649]--NBA Finals(dp,后台略(hen)坑)

    题目链接:http://acm.swust.edu.cn/problem/649/ Time limit(ms): 1000 Memory limit(kb): 65535 Consider two ...

  5. java 如何自定义异常 用代码展示 真心靠谱

    先建两个自定义的异常类 ChushufuException类 class ChushufuException extends Exception { public ChushufuException( ...

  6. 20150706 js之定时器

    对应智能社:09 定时器的使用 开启定时器: setInterval(xxx(),1000);//间隔型 第一个参数为函数,第二个为时间,单位为毫秒 setTimeout(xxx(),1000);// ...

  7. ZOJ 2856 Happy Life 暴力求解

    因为是Special Judge 的题目,只要输出正确答案即可,不唯一 暴力力求解, 只要每次改变 happiness 值为负的人的符号即可. 如果计算出当前人的 happiness 值为负,那么将其 ...

  8. POJ1054 枚举【STL__binary_search()_的应用】

    ①使用binary_search前要先保证有序 ②binary_search函数仅返回true或false ③binary_search(first element, laste lment + 1, ...

  9. 【HTTP 2】简介(Introduction)

    前情提要 在上一篇文章<[HTTP 2.0] 序言>中,我们简要介绍了 HTTP 2 协议的概要和协议状态. 在本篇文章中,我们将会了解到 HTTP 2 协议简介(Introduction ...

  10. php 解析url 和parse_url使用

    通过url进行传值,是php中一个传值的重要手段.所以我们要经常对url里面所带的参数进行解析,如果我们知道了url传递参数名称,例如 /index.php?name=tank&sex=1#t ...