在查询或者更新数据的时候我们都容易犯忘记关闭JDBC的错误,spring之类的框架又非常笨重,DbUtils 是一个非常轻量的操作JDBC的工具。
除了操作简便之外,dbutils还可以将ResultSet转换成不同的对象。
使用示例
1 | /* |
其中_DATASOURCEMAP数组存放的是线程池,初始化_DATASOURCEMAP:1
2
3
4
5
6
7private static final Map<String, DataSource> _DATASOURCEMAP = new ConcurrentHashMap<>();
...
for (final Map<String, Object> row : (List<Map<String, Object>>) config.get("node")) {
//System.out.println(row.get("aliasName"));
_CONFIG.put(row.get("aliasName").toString(), row); /*把节点缓存*/
_DATASOURCEMAP.put(row.get("aliasName").toString(), DruidDataSourceFactory.createDataSource(row));
}
这部分有个druid的线程池的部分,关于druid的可以参考博客中的druid源码阅读。
其中调用queryrunner实例的部分:1
2final QueryRunner qr = MySQLHelper.getQueryRunner();
final List<Map<String, Object>> result = qr.query(sql, new MapListHandler());
进入正题
重要的几个类:
DbUtils 工具类
定义了close、加载驱动等静态方法。QueryRunner
查询的入口类,对应的AsyncQueryRunner是异步的query,执行查询sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params)
throws SQLException {
...
try {
stmt = this.prepareStatement(conn, sql);
this.fillStatement(stmt, params); //填充参数
rs = this.wrap(stmt.executeQuery());
result = rsh.handle(rs);
} catch (SQLException e) {
this.rethrow(e, sql, params);
} finally {
try {
close(rs);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}
}
return result;
}update 方法执行更新操作SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14try {
stmt = this.prepareStatement(conn, sql);
this.fillStatement(stmt, params);
rows = stmt.executeUpdate();
} catch (SQLException e) {
this.rethrow(e, sql, params);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}insert方法,执行插入操作SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try {
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
this.fillStatement(stmt, params);
stmt.executeUpdate();
ResultSet resultSet = stmt.getGeneratedKeys();
generatedKeys = rsh.handle(resultSet);
} catch (SQLException e) {
this.rethrow(e, sql, params);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}insertBatch,批量插入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19try {
stmt = this.prepareStatement(conn, sql, Statement.RETURN_GENERATED_KEYS);
for (int i = 0; i < params.length; i++) {
this.fillStatement(stmt, params[i]);
stmt.addBatch();
}
stmt.executeBatch();
ResultSet rs = stmt.getGeneratedKeys();
generatedKeys = rsh.handle(rs);
} catch (SQLException e) {
this.rethrow(e, sql, (Object[])params);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}batch,批量更新:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17try {
stmt = this.prepareStatement(conn, sql);
for (int i = 0; i < params.length; i++) {
this.fillStatement(stmt, params[i]);
stmt.addBatch();
}
rows = stmt.executeBatch();
} catch (SQLException e) {
this.rethrow(e, sql, (Object[])params);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}ResultSetHandler
接口,负责把ResultSet的结果转换成指定的对象
1 | /** |
比如比较常用的
MapHandler
是将结果集的数据封装到了Map里,其中key是列名,Value是对应的值。
1 | public class MapHandler implements ResultSetHandler<Map<String, Object>> { |
MapListHandler
将结果集的每一行都存到map里,然后再存放到List中。1
2
3
4
5
6public class MapListHandler extends AbstractListHandler<Map<String, Object>> {
@Override
protected Map<String, Object> handleRow(ResultSet rs) throws SQLException {
return this.convert.toMap(rs);
}
}
两者的转换行数据的方法都是toMap,关键在于,MapHandler扩展的是ResultSetHandler
,
MapListHanddler扩展的是AbstractListHandler
:1
2
3
4
5
6
7
8@Override
public List<T> handle(ResultSet rs) throws SQLException {
List<T> rows = new ArrayList<T>();
while (rs.next()) {
rows.add(this.handleRow(rs));
}
return rows;
}
RowProcessor
为ResultSetHandler转换行数据。比如
toArray:1
2
3
4
5
6
7
8
9
10
11
12@Override
public Object[] toArray(ResultSet rs) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
Object[] result = new Object[cols];
for (int i = 0; i < cols; i++) {
result[i] = rs.getObject(i + 1);
}
return result;
}
toMap:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Override
public Map<String, Object> toMap(ResultSet rs) throws SQLException {
Map<String, Object> result = new CaseInsensitiveHashMap();
ResultSetMetaData rsmd = rs.getMetaData();
int cols = rsmd.getColumnCount();
for (int i = 1; i <= cols; i++) {
String columnName = rsmd.getColumnLabel(i);
if (null == columnName || 0 == columnName.length()) {
columnName = rsmd.getColumnName(i);
}
result.put(columnName, rs.getObject(i));
}
return result;
}
参考资料
PreparedStatement详解
Apache Commons DbUtils 源码分析 | Apache Commons DbUtils Source Code Analysis