commons-dbutils-1.9.3.jar 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低, 并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
0、Dbutils的query()的实现原理:
1、万变不离其宗,查询方法只不过是封装了结果集ResultSet转换为map或list的过程。
2、具体实现方法:
(1)以BeanListHandler为例,我们期望“将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里”。代码如下:
Connection connection = JdbcUtils.getConnection();
List userList = new ArrayList<>();
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new BeanListHandler(User.class);
userList = runner.query(connection,sql,rsh);
在上一篇博文说道,使用Statement或PreparedStatement执行查询,得到结果集ResultSet,然后对结果集遍历,再进行封装处理:
public static List statementExecuteQuery(Class clazz, final String sql){
T entity = null;
Statement statement = null;
ResultSet resultSet = null;
List queryResult = new ArrayList<>();
Connection connection= getConnection();
if (null == connection){
//log.error("Connection is null.");
return null;
}
try {
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);//过程一:得到结果集
final List
private static List
问:Dbutils是怎么做到封装的呢? 先看看查询实现代码:
List entityList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new BeanListHandler(User.class);
entityList = (List)runner.query(connection,sql,rsh);
其实很简单,就是把上面三个过程做了封装而已,封装到 runner.query(connection,sql,rsh) 方法中。
仔细一点就是,queryRunner.query(con,sql,rsh)方法有三个参数,第一个是数据库连接对象,第二个是执行数据库查询的sql语句,第三个很重主要了,就是结果集处理ResultSetHandler的实现类。也就是你要将查询出来的一什么形式返回,是返回一个数组,还是JavaBean实例,还是Map结果,还是一个具体的结果ScalarHandler。
ResultSetHandler接口,有一个 handler 方法,queryRunner.query(con,sql,rsh) 方法将查询出来的结果集交给handler 方法来进行处理,按照 rsh 具体实现类的类型来封装处理结果集。
看看源代码:
ResultSetHandler接口:
public interface ResultSetHandler {
T handle(ResultSet var1) throws SQLException;
}
queryRunner.query(con,sql,rsh)方法:
public T query(Connection conn, String sql, ResultSetHandler rsh) throws SQLException {
return this.query(conn, false, sql, rsh, (Object[])null);
}
private T query(Connection conn, boolean closeConn, String sql, ResultSetHandler rsh, Object... params) throws SQLException {
//略去如参判断code
PreparedStatement stmt = null;
ResultSet rs = null;
Object result = null;
try {
stmt = this.prepareStatement(conn, sql);
this.fillStatement(stmt, params);
rs = this.wrap(stmt.executeQuery());
result = rsh.handle(rs);//调用handler方法,处理结果集。
} catch (SQLException var33) {
this.rethrow(var33, sql, params);
} finally {
try {
this.close(rs);
} finally {
this.close(stmt);
if (closeConn) {
this.close(conn);
}
}
}
return result;
}
BeanListHandler实现类的handler方法如何处理结果集:
public class BeanListHandler implements ResultSetHandler> {
private final Class extends T> type;
private final RowProcessor convert;
public BeanListHandler(Class extends T> type) {
this(type, ArrayHandler.ROW_PROCESSOR);
}
public BeanListHandler(Class extends T> type, RowProcessor convert) {
this.type = type;
this.convert = convert;
}
//调用RowProcessor对象的toBeanLit方法处理结果集方法
public List handle(ResultSet rs) throws SQLException {
return this.convert.toBeanList(rs, this.type);
}
}
RowProcessor类的toBeanList()方法:
public List toBeanList(ResultSet rs, Class extends T> type) throws SQLException {
List results = new ArrayList();
if (!rs.next()) {
return results;
} else {
PropertyDescriptor[] props = this.propertyDescriptors(type);
ResultSetMetaData rsmd = rs.getMetaData();
int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
do {
results.add(this.createBean(rs, type, props, columnToProperty));
} while(rs.next());
return results;
}
}
不信,我们可以测试一波:
public static void main(String[] args){
String selectSql = "SELECT * FROM userinfos WHERE userName = 'aerfa';";
Object object = dbutilsExecuteQueryUserOne(selectSql);
System.out.println(object);
}
static class MyResultSetHandler implements ResultSetHandler{
@Override
public Object handle(ResultSet var1) throws SQLException{
System.out.println("This my ResultSetHandler.");
return "myResultSetHandler";
}
}
public static Object dbutilsExecuteQueryUserOne(final String sql){
Object user = null;
Connection connection = JdbcUtils.getConnection();
if(null == connection){
return null;
}
try {
user = new User();
QueryRunner runner = new QueryRunner();
ResultSetHandler rsh = new MyResultSetHandler();
user = runner.query(connection,sql,rsh);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return user;
}
测试结果:
ResultSetHandler的各个实现类:
ArrayHandler:把结果集中的第一行数据转成对象数组。
ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List。
ColumnListHandler:将结果集中某一列的数据存放到List中。
KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List
ScalarHandler:将结果集第一行的某一列放到某个对象。
使用遵从以下步骤:
1.加载JDBC驱动程序类,并用DriverManager来得到一个数据库连接conn。
2.实例化 QueryRunner,得到实例化对象runner。
3. runner.update()方法,执行增改删的sql命令,runner.query()方法,得到结果集。
1、使用MapHandler查询单个结果
public static User dbutilsExecuteQueryUserOne(final String sql){
User user = null;
Connection connection = JdbcUtils.getConnection();
if(null == connection){
return null;
}
try {
user = new User();
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new MapHandler();
Map data = runner.query(connection,sql,rsh);
for(Map.Entry entry : data.entrySet()){
String colunName = entry.getKey();
Object colunValue = entry.getValue();
BeanUtils.setProperty(user,colunName,colunValue);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return user;
}
2、使用MapListHandler查询多个结果
public static List dbutilsExecuteQueryUsersOne(final String sql){
List userList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler>> rsh = new MapListHandler();
List> data = runner.query(connection,sql,rsh);
for (Map map : data){
User user = new User();
for (Map.Entry entry : map.entrySet()){
String columnName = entry.getKey();
Object columnValue = entry.getValue();
BeanUtils.setProperty(user,columnName,columnValue);
}
userList.add(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return userList;
}
3、使用BeanHandler查询单个结果
public static User dbutilsExecuteQueryUserTwo(final String sql){
User user = null;
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler rsh = new BeanHandler(User.class);
user = runner.query(connection,sql,rsh);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return user;
}
4、使用BeanListHandler查询多个结果
public static List dbutilsExecuteQueryUsersTwo(final String sql){
List userList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new BeanListHandler(User.class);
userList = runner.query(connection,sql,rsh);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return userList;
}
5、利用反射机制,查询方法通用化
public static T dbutilsExecuteQueryUserOne(Class clazz, final String sql){
T entity = null;
Connection connection = JdbcUtils.getConnection();
if(null == connection){
return null;
}
try {
entity = clazz.newInstance();
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new MapHandler();
Map data = runner.query(connection,sql,rsh);
for(Map.Entry entry : data.entrySet()){
String colunName = entry.getKey();
Object colunValue = entry.getValue();
BeanUtils.setProperty(entity,colunName,colunValue);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entity;
}
public static List dbutilsExecuteQueryUsersOne(Class clazz, final String sql){
List entityList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler>> rsh = new MapListHandler();
List> data = runner.query(connection,sql,rsh);
for (Map map : data){
T entity = clazz.newInstance();
for (Map.Entry entry : map.entrySet()){
String columnName = entry.getKey();
Object columnValue = entry.getValue();
BeanUtils.setProperty(entity,columnName,columnValue);
}
entityList.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entityList;
}
public static T dbutilsExecuteQueryUserTwo(Class clazz, final String sql){
T entity = null;
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler rsh = new BeanHandler(User.class);
entity = (T) runner.query(connection,sql,rsh);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entity;
}
public static List dbutilsExecuteQueryUsersTwo(Class clazz, final String sql){
List entityList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new BeanListHandler(User.class);
entityList = (List)runner.query(connection,sql,rsh);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entityList;
}
查询:可接受带有填充字符的sql语句,可防止sql注入。
public static T queryByMapHandler(Class clazz, final String sql,Object...args){
T entity = null;
Connection connection = JdbcUtils.getConnection();
if(null == connection){
return null;
}
try {
entity = clazz.newInstance();
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new MapHandler();
Map data = runner.query(connection,sql,rsh,args);
for(Map.Entry entry : data.entrySet()){
String colunName = entry.getKey();
Object colunValue = entry.getValue();
BeanUtils.setProperty(entity,colunName,colunValue);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entity;
}
public static List queryByMapListHandler(Class clazz, final String sql, Object...args){
List entityList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler>> rsh = new MapListHandler();
List> data = runner.query(connection,sql,rsh,args);
for (Map map : data){
T entity = clazz.newInstance();
for (Map.Entry entry : map.entrySet()){
String columnName = entry.getKey();
Object columnValue = entry.getValue();
BeanUtils.setProperty(entity,columnName,columnValue);
}
entityList.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entityList;
}
public static T queryByBeanHandler(Class clazz, final String sql, Object...args){
T entity = null;
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler rsh = new BeanHandler(User.class);
entity = (T) runner.query(connection,sql,rsh,args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entity;
}
public static List queryByBeanListHandler(Class clazz, final String sql,Object...args){
List entityList = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return null;
}
try {
QueryRunner runner = new QueryRunner();
ResultSetHandler> rsh = new BeanListHandler(User.class);
entityList = (List)runner.query(connection,sql,rsh,args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
return entityList;
}
6、执行插入、删除、更新操作
/**
* 可执行插入、删除、更新操作
* @param sql:一条完整的sql语句
*/
public static void executeByUpdate(final String sql){
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return;
}
try {
QueryRunner runner = new QueryRunner();
int num = runner.update(connection, sql);
if (0 == num) {
//log.error("execute update failed.");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
}
/**
* 可执行插入、删除、更新操作
* @param sql:带有可填充的sql语句
*/
public static void executeByUpdate(final String sql, Object... args){
Connection connection = JdbcUtils.getConnection();
if (null == connection){
return;
}
try {
QueryRunner runner = new QueryRunner();
int num = runner.update(connection, sql, args);
if (0 == num) {
//log.error("execute update failed.");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(connection,null,null,null);
}
}
参考:
使用DbUtils实现增删改查——ResultSetHandler 接口的实现类
利用ResultSetHandler各实现类来处理查询结果
开源工具DbUtils的使用(数据库的增删改查)
DbUtils
开源框架:DBUtils使用详解