Commons DbUtils是Apache提供的一個對JDBC進行簡單封裝的開源工具類庫,可以簡化JDBC相關的開發。Commons DbUtils能夠很是方便的整合Spring Framework,比較輕量級,執行SQL語句很是方便(特別是查詢語句),能夠代替Spring JdbcTemplate、MyBatis等數據庫訪問層技術。java
DbUtils經過QueryRunner
類來執行SQL,使用起來很是相似於Spring框架中的JdbcTemplate
。mysql
<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等。spring
因爲DbUtils自己不支持Spring事務,若是想要支持事務,例如@Transactional
註解,還須要給DataSource加一層代理:sql
<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:數據庫
public class UserDao { @Autowired private QueryRunner queryRunner; }
增刪改操做,也就是INSERT、DELETE、UPDATE語句,均可以經過QueryRunner的execute方法來直接執行:apache
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中帶有參數的。app
ResultSetHandler
是DbUtils中的一個接口,該接口的實現類可用於將JDBC查詢語句返回的結果(也就是ResultSet
),轉成你想要的數據類型。這個和Spring JdbcTemplate查詢時用到的RowMapper
接口很是相似。框架
下面寫了一個ResultSetHandler
實現類,將一條SQL的查詢結果轉爲一個List<User>:ide
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; });
DbUtils提供了一些經常使用的ResultSetHandler
實現類,能夠簡化查詢,通常狀況下不須要像上面那樣本身來實現ResultSetHandler
接口。
用於返回查詢結果第一行第一列數據:
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的用戶的用戶名
返回查詢結果(全部行)第一列的數據List:
List<String> userNameList = queryRunner.query("select user_name from user_info", new ColumnListHandler<String>()); // 查詢全部用戶的user_name
返回查詢結果第一行數據(全部列)並組裝成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");
和MapHandler
機制相似,MapListHandler
會將ResultSet轉成一個List<Map<String, Object>>
:
List<Map<String, Object>> dataList = queryRunner.query("select user_id,user_name from user_info", new MapListHandler());
返回查詢結果第一行數據,將全部列值按順序組成一個數據:
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];
和ArrayHandler
機制相似,ArrayListHandler
會將ResultSet轉成一個List<Object[]>
:
List<Object[]> list = queryRunner.query("select user_id,user_name from user_info", new ArrayListHandler());
將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
是比較實用的一個類,能夠經過反射機制將查詢結果第一行數據根據數據庫列名映射到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())));
和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())));
相似於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的用戶