文章目录
  1. 1. 配置
  2. 2. 增删改
  3. 3. 查询
    1. 3.1. ResultSetHandler
    2. 3.2. 常用ResultSetHandler实现类
      1. 3.2.1. ScalarHandler
      2. 3.2.2. ColumnListHandler
      3. 3.2.3. MapHandler
      4. 3.2.4. MapListHandler
      5. 3.2.5. ArrayHandler
      6. 3.2.6. ArrayListHandler
      7. 3.2.7. KeyedHandler
      8. 3.2.8. BeanHandler
      9. 3.2.9. BeanListHandler
      10. 3.2.10. BeanMapHandler

Commons DbUtils是Apache提供的一个对JDBC进行简单封装的开源工具类库,能够简化JDBC相关的开发。Commons DbUtils可以非常方便的整合Spring Framework,比较轻量级,执行SQL语句非常方便(特别是查询语句),可以代替Spring JdbcTemplate、MyBatis等数据库访问层技术。

配置

DbUtils通过QueryRunner类来执行SQL,使用起来非常类似于Spring框架中的JdbcTemplate

1
2
3
4
5
6
7
8
9
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test_db" />
<property name="username" value="root" />
<property name="password" value="xxx" />
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg ref="dataSource" />
</bean>

我这里使用的连接池是HikariCP,这里可以根据需要换成其他的连接池,例如DBCP、Druid等。

由于DbUtils本身不支持Spring事务,如果想要支持事务,例如@Transactional注解,还需要给DataSource加一层代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource">
<bean class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test_db" />
<property name="username" value="root" />
<property name="password" value="xxx" />
</bean>
</property>
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg ref="dataSource" />
</bean>

Java代码中可以通过Autowired引入QueryRunner:

1
2
3
4
5
public class UserDao {

@Autowired
private QueryRunner queryRunner;
}

增删改

增删改操作,也就是INSERT、DELETE、UPDATE语句,都可以通过QueryRunner的execute方法来直接执行:

1
2
queryRunner.execute("delete from user_info");
queryRunner.execute("update user_info set user_name=?,user_age=? where user_id=?", "xxg", 28, 6);

由于DbUtils本身也是基于JDBC中的PreparedStatement来实现的,所以也是支持SQL中带有参数的。

查询

ResultSetHandler

ResultSetHandler是DbUtils中的一个接口,该接口的实现类可用于将JDBC查询语句返回的结果(也就是ResultSet),转成你想要的数据类型。这个和Spring JdbcTemplate查询时用到的RowMapper接口非常类似。

下面写了一个ResultSetHandler实现类,将一条SQL的查询结果转为一个List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<User> list = queryRunner.query("select * from user_info limit 100", new ResultSetHandler<List<User>>() {
@Override
public List<User> handle(ResultSet rs) throws SQLException {
List<User> l = new ArrayList<User>();
while (rs.next()) {
User user = new User();
user.setUserId(rs.getInt("user_id"));
user.setUserName(rs.getString("user_name"));
user.setCreateTime(rs.getTimestamp("create_time"));
l.add(user);
}
return l;
}
});

由于ResultSetHandler接口中只有一个抽象方法,所以如果是Java 8版本的话也可以使用Lambda表达式来简化代码:

1
2
3
4
5
6
7
8
9
10
11
List<User> list = queryRunner.query("select * from user_info limit 100", rs -> {
List<User> l = new ArrayList<User>();
while (rs.next()) {
User user = new User();
user.setUserId(rs.getInt("user_id"));
user.setUserName(rs.getString("user_name"));
user.setCreateTime(rs.getTimestamp("create_time"));
l.add(user);
}
return l;
});

常用ResultSetHandler实现类

DbUtils提供了一些常用的ResultSetHandler实现类,可以简化查询,一般情况下不需要像上面那样自己来实现ResultSetHandler接口。

ScalarHandler

用于返回查询结果第一行第一列数据:

1
2
long count = queryRunner.query("select count(*) from user_info", new ScalarHandler<Long>()); // 查询count
String userName = queryRunner.query("select user_name from user_info where user_id=?", new ScalarHandler<String>(), 1); // 查询user_id=1的用户的用户名

ColumnListHandler

返回查询结果(所有行)第一列的数据List:

1
List<String> userNameList = queryRunner.query("select user_name from user_info", new ColumnListHandler<String>()); // 查询所有用户的user_name

MapHandler

返回查询结果第一行数据(所有列)并组装成Map,Map的key为列名,value为值:

1
2
3
Map<String, Object> userInfo = queryRunner.query("select user_id,user_name from user_info where user_id=1", new MapHandler());
long userId = (Long) userInfo.get("user_id");
String userName = (String) userInfo.get("user_name");

MapListHandler

MapHandler机制类似,MapListHandler会将ResultSet转成一个List<Map<String, Object>>

1
List<Map<String, Object>> dataList = queryRunner.query("select user_id,user_name from user_info", new MapListHandler());

ArrayHandler

返回查询结果第一行数据,将所有列值按顺序组成一个数据:

1
2
3
Object[] data = queryRunner.query("select user_id,user_name from user_info where user_id=1", new ArrayHandler());
long userId = (Long) data[0];
String userName = (String) data[1];

ArrayListHandler

ArrayHandler机制类似,ArrayListHandler会将ResultSet转成一个List<Object[]>

1
List<Object[]> list = queryRunner.query("select user_id,user_name from user_info", new ArrayListHandler());

KeyedHandler

将ResultSet转为Map<?, Map<String, Object>>,外层Map每个元素对应查询结果的一条数据,key为数据的主键或者唯一索引,value也是一个Map,内容是一行数据的列名和值,和MapHandler机制类似:

1
2
3
4
Map<Long, Map<String, Object>> dataMap = queryRunner.query("select user_id,user_name from user_info", new KeyedHandler<Long>("user_id")); // Key指定为user_id列
Map<String, Object> data = dataMap.get(1L); // 获取user_id=1的一条记录
long userId = (Long) data.get("user_id");
String userName = (String) data.get("user_name");

BeanHandler

BeanHandler是比较实用的一个类,可以通过反射机制将查询结果第一行数据根据数据库列名映射到Java对象上,先定义一个Java对象:

1
2
3
4
5
6
7
8
9
public class User {

private int userId;
private String userName;
private int userAge;
private Date createTime;

// 省略getter setter
}

执行查询:

1
2
// 查询user_id=1的用户数据并返回User对象
User user = queryRunner.query("select user_id as userId,user_name as userName,user_age as userAge,create_time as createTime from user_info where user_id=1", new BeanHandler<User>(User.class));

数据库列名很多人会使用下划线作为单词间分隔符,而Java命名规范要求变量名是驼峰命名,这样会导致无法直接映射,所以上面代码中在SQL语句上通过AS将列名下划线分隔符转成驼峰命名。但是如果字段比较多,或者想使用select *查询,上面的这种方法就不好使了。下面提供一种方案,可以将带有下划线分隔符的列名映射到驼峰命名的Java对象上:

1
2
User user = queryRunner.query("select user_id,user_name,user_age,create_time from user_info where user_id=1",
new BeanHandler<User>(User.class, new BasicRowProcessor(new GenerousBeanProcessor())));

BeanListHandler

BeanHandler机制类似,BeanListHandler可以将多条查询结果转为Java Bean的List:

1
2
List<User> userList = queryRunner.query("select user_id as userId,user_name as userName,user_age as userAge,create_time as createTime from user_info",
new BeanListHandler<User>(User.class));

同样也可以将带有下划线分隔符的列名映射到驼峰命名的Java对象上:

1
2
List<User> userList = queryRunner.query("select user_id,user_name,user_age,create_time from user_info",
new BeanListHandler<User>(User.class, new BasicRowProcessor(new GenerousBeanProcessor())));

BeanMapHandler

类似于KeyedHandler机制,将ResultSet转为一个Map,Map中每条数据对应查询结果的一条数据,key为数据的主键或者唯一索引,value是数据通过反射机制转成的Java对象:

1
2
3
Map<Long, User> users = queryRunner.query("select user_id as userId,user_name as userName,user_age as userAge,create_time as createTime from user_info",
new BeanMapHandler<Long, User>(User.class, "userId")); // 使用userId列作为Map的key
User user1 = users.get(1L); // 获取user_id=1的用户

同样也可以将带有下划线分隔符的列名映射到驼峰命名的Java对象上:

1
2
3
4
// Map的key默认使用查询语句中的第一列(即主键user_id)
Map<Long, User> users = queryRunner.query("select user_id,user_name,user_age,create_time from user_info",
new BeanMapHandler<Long, User>(User.class, new BasicRowProcessor(new GenerousBeanProcessor())));
User user1 = users.get(1L); // 获取user_id=1的用户

文章目录
  1. 1. 配置
  2. 2. 增删改
  3. 3. 查询
    1. 3.1. ResultSetHandler
    2. 3.2. 常用ResultSetHandler实现类
      1. 3.2.1. ScalarHandler
      2. 3.2.2. ColumnListHandler
      3. 3.2.3. MapHandler
      4. 3.2.4. MapListHandler
      5. 3.2.5. ArrayHandler
      6. 3.2.6. ArrayListHandler
      7. 3.2.7. KeyedHandler
      8. 3.2.8. BeanHandler
      9. 3.2.9. BeanListHandler
      10. 3.2.10. BeanMapHandler