本文包括:
1、DBUtils簡介
2、DbUtils類
3、QueryRunner類
4、ResultSetHandler接口
5、使用步驟
1、DbUtils簡介
commons-dbutils 是 Apache 組織提供的一個開源 JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,并且使用dbutils能極大簡化jdbc編碼的工作量,創建連接、結果集封裝、釋放資源,同時也不會影響程序的性能。創建連接、結果集封裝、釋放資源因此dbutils成為很多不喜歡hibernate的公司的首選。
-
API介紹:
- org.apache.commons.dbutils.QueryRunner --- 核心
- org.apache.commons.dbutils.ResultSetHandler --- 結果集封裝器
- org.apache.commons.dbutils.DbUtils --- 工具類
學習重點:多看看API,多看看官網的example!
2、DbUtils類
DbUtils :提供如加載驅動、關閉連接、事務提交、回滾等常規工作的工具類,里面的所有方法都是靜態的。主要方法如下:
-
DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉Connection、Statement和ResultSet。
public static void close(…) throws java.sql.SQLException
-
這一類"quietly"方法不僅能在Connection、Statement和ResultSet為NULL情況下避免關閉,還能隱藏一些在程序中拋出的SQLException。
public static void closeQuietly(…)
-
用來提交連接,然后關閉連接,并且在關閉連接時不拋出SQL異常。
public static void commitAndCloseQuietly(Connection conn)
-
裝載并注冊JDBC驅動程序,如果成功就返回true。使用該方法,你不需要捕捉這個異常ClassNotFoundException。
public static boolean loadDriver(java.lang.String driverClassName)
3、QueryRunner類
該類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的數據庫操作,能夠大大減少編碼量。
-
QueryRunner類提供了兩個構造方法:
默認的構造方法:QueryRunner()
-
需要一個 javax.sql.DataSource 來作參數的構造方法:QueryRunner(DataSource ds)
注意:構造器需要傳入DataSource參數,所以必須要用到連接池,關于JDBC連接池可參考我之前的一篇文章:《JDBC進階——連接池》。在那篇文章中的JDBCUtils類中沒有相應的方法來獲得DataSource對象,所以應該在JDBCUtils類中加入如下代碼:
// 返回數據庫連接池 public static DataSource getDataSource() { return dataSource; }
-
常用方法(分為兩種情況):
-
批處理
batch(Connection conn, String sql, Object[][] params) // 傳遞連接批處理 batch(String sql, Object[][] params) // 不傳遞連接批處理
-
查詢操作
public Object query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) public Object query(String sql, ResultSetHandler<T> rsh, Object... params)
-
更新操作
public int update(Connection conn, String sql, Object... params) public int update(String sql, Object... params)
-
4、ResultSetHandler接口
該接口用于處理 java.sql.ResultSet,將數據按要求轉換為另一種形式。
-
ResultSetHandler 接口提供了一個單獨的方法:
Object handle(ResultSet rs){}
-
ResultSetHandler 接口的實現類(構造方法不唯一,在這里只用最常見的構造方法):
ArrayHandler():把結果集中的第一行數據轉成對象數組(存入Object[])。
ArrayListHandler():把結果集中的每一行數據都轉成一個對象數組,再存放到List中。
BeanHandler(Class
<T>
type):將結果集中的第一行數據封裝到一個對應的JavaBean實例中。-
BeanListHandler(Class
<T>
type):將結果集中的每一行數據都封裝到一個對應的JavaBean實例中,存放到List里。Parameters:
type - The Class that objects returned from handle() are created from.
ColumnListHandler(String columnName/int columnIndex):將結果集中某一列的數據存放到List中。
MapHandler():將結果集中的第一行數據封裝到一個Map里,key是列名,value就是對應的值。
MapListHandler():將結果集中的每一行數據都封裝到一個Map里,然后再將所有的Map存放到List中。
KeyedHandler(String columnName):將結果集每一行數據保存到一個“小”map中,key為列名,value該列的值,再將所有“小”map對象保存到一個“大”map中 , “大”map中的key為指定列,value為“小”map對象
ScalarHandler(int columnIndex):通常用來保存只有一行一列的結果集。
注意:DBUtils-1.4版本中的 ScalarHandler, ColumnHandler, and KeyedHandler沒有泛型!要使用1.5以上的版本。
Release Notes Address : http://commons.apache.org/proper/commons-dbutils/changes-report.html
5、使用步驟
將DBUtils的jar包加入到項目工程的build path中。
-
對于CUD,有兩種不同的情況:
-
情況一:
如果使用 QueryRunner(DataSource ds) 構造器創建QueryRunner對象,需要使用連接池,如DBCP、C3P0等等,數據庫事務交給DBUtils框架進行管理 ---- 默認情況下每條SQL語句單獨一個事務。
-
在這種情況下,使用如下方法:
batch(String sql, Object[][] params) query(String sql, ResultSetHandler<T> rsh, Object... params) update(String sql, Object... params)
-
demo:
@Test public void testDelete() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "delete from users where id = ?"; queryRunner.update(sql, 3); } @Test public void testUpdate() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "update users set password = ? where username = ?"; Object[] param = { "nihao", "小明" }; queryRunner.update(sql, param); } @Test public void testInsert() throws SQLException { // 第一步 創建QueryRunner對象 QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); // 第二步 準備方法參數 String sql = "insert into users values(null,?,?,?)"; Object[] param = { "小麗", "qwe", "xiaoli@itcast.cn" }; // 第三步 調用 query / update queryRunner.update(sql, param); }
-
-
情況二:
如果使用 QueryRunner() 構造器創建QueryRunner對象 ,需要自己管理事務,因為框架沒有連接池無法獲得數據庫連接。
-
在這種情況下,要使用傳入Connection對象參數的方法:
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) update(Connection conn, String sql, Object... params)
-
demo:
// 事務控制 @Test public void testTransfer() throws SQLException { double money = 100; String outAccount = "aaa"; String inAccount = "bbb"; String sql1 = "update account set money = money - ? where name= ?"; String sql2 = "update account set money = money + ? where name= ?"; // 傳入DataSource的構造器,默認每條SQL語句一個單獨事務,而在這里要自己管理業務,所以不合適! // QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); QueryRunner queryRunner = new QueryRunner();// 不要傳遞連接池 --- 手動事務管理 Connection conn = JDBCUtils.getConnection(); conn.setAutoCommit(false); try { queryRunner.update(conn, sql1, money, outAccount); // 注意要傳入Connection對象的方法 // int d = 1 / 0; queryRunner.update(conn, sql2, money, inAccount); System.out.println("事務提交!"); DbUtils.commitAndCloseQuietly(conn); } catch (Exception e) { System.out.println("事務回滾!"); DbUtils.rollbackAndCloseQuietly(conn); e.printStackTrace(); } }
-
-
-
對于R,需要用到ResultSetHandler接口,該接口有9大實現類,
public class ResultSetHandlerTest { // ScalarHandler 通常用于保存只有一行一列的結果集,例如分組函數 @Test public void demo9() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select count(*) from account"; long count = (Long) queryRunner.query(sql, new ScalarHandler(1)); // 得到結果集的第1列 System.out.println(count); } // KeyedHandler 將結果集每一行數據保存到一個“小”map中,key為列名,value該列的值,再將所有“小”map對象保存到一個“大”map中 , “大”map中的key為指定列,value為“小”map對象 @Test public void demo8() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; Map<Object, Map<String, Object>> map = queryRunner.query(sql, new KeyedHandler("id")); System.out.println(map); } // MapListHandler 將結果集每一行數據保存到map中,key列名 value該列的值 ---- 再將所有map對象保存到List集合中 @Test public void demo7() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; List<Map<String, Object>> list = queryRunner.query(sql, new MapListHandler()); for (Map<String, Object> map : list) { System.out.println(map); } } // MapHander 將結果集第一行數據封裝到Map集合中,key是列名,value為該列的值 @Test public void demo6() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; Map<String, Object> map = queryRunner.query(sql, new MapHandler()); // 列名為String類型,該列的值為Object類型 System.out.println(map); } // ColumnListHandler 獲得結果集的某一列,將該列的所有值存入List<Object>中 @Test public void demo5() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 因為每列類型都不一樣,所以用List<Object>存儲 // List<Object> list = queryRunner.query(sql, // new ColumnListHandler("name")); // 得到表列名為name的列 List<Object> list = queryRunner.query(sql, new ColumnListHandler(2)); // 得到結果集的第2列 System.out.println(list); } // BeanListHander 將結果集每一條數據,轉為JavaBean對象,再保存到list集合中 @Test public void demo4() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; List<Account> accounts = queryRunner.query(sql, new BeanListHandler<Account>(Account.class)); for (Account account : accounts) { System.out.println(account.getId()); System.out.println(account.getName()); System.out.println(account.getMoney()); System.out.println("----------------"); } } // BeanHandler 將結果集第一行數據封裝到JavaBean對象中 @Test public void demo3() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 傳入 Account.class字節碼文件:為了在方法中 通過反射構造Account對象 // 使用BeanHandler注意事項 :數據庫中的表列名 與 Bean類中屬性 名稱一致!!! Account account = queryRunner.query(sql, new BeanHandler<Account>( Account.class)); System.out.println(account.getId()); System.out.println(account.getName()); System.out.println(account.getMoney()); } // ArrayListHandler 將結果集每一行數據保存到List<Object[]>中 @Test public void demo2() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; List<Object[]> list = queryRunner.query(sql, new ArrayListHandler()); for (Object[] objects : list) { System.out.println(Arrays.toString(objects)); } } // ArrayHandler 將結果集第一行數據保存到Object[]中 @Test public void demo1() throws SQLException { // 使用DBUtils QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 對象數組存儲rs第一行數據的所有列 Object[] values = queryRunner.query(sql, new ArrayHandler()); System.out.println(Arrays.toString(values)); } }
JDBC文集:
Java 與數據庫的橋梁——JDBC:http://www.lxweimin.com/p/c0acbd18794c
JDBC 進階——連接池:http://www.lxweimin.com/p/ad0ff2961597
JDBC 進階——元數據:http://www.lxweimin.com/p/36d5d76342f1
JDBC框架——DBUtils:http://www.lxweimin.com/p/10241754cdd7