54

Apache Commons DbUtils整合Spring框架实现简单的CRUD

 5 years ago
source link: http://xxgblog.com/2018/08/30/dbutils-spring/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

配置

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

<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等。

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

public class UserDao {

    @Autowired
    private QueryRunner queryRunner;
}

增删改

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

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

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表达式来简化代码:

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

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

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:

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

MapHandler

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

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>>

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

ArrayHandler

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

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[]>

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 机制类似:

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对象:

public class User {

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

    // 省略getter setter
}

执行查询:

// 查询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对象上:

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:

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对象上:

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对象:

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对象上:

// 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的用户

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK