本文包括:
1计雌、DBUtils簡(jiǎn)介
2荣赶、DbUtils類
3昧谊、QueryRunner類
4刽虹、ResultSetHandler接口
5、使用步驟
1呢诬、DbUtils簡(jiǎn)介
commons-dbutils 是 Apache 組織提供的一個(gè)開源 JDBC工具類庫涌哲,它是對(duì)JDBC的簡(jiǎn)單封裝,學(xué)習(xí)成本極低尚镰,并且使用dbutils能極大簡(jiǎn)化jdbc編碼的工作量阀圾,創(chuàng)建連接、結(jié)果集封裝狗唉、釋放資源初烘,同時(shí)也不會(huì)影響程序的性能。創(chuàng)建連接、結(jié)果集封裝账月、釋放資源因此dbutils成為很多不喜歡hibernate的公司的首選。
-
API介紹:
- org.apache.commons.dbutils.QueryRunner --- 核心
- org.apache.commons.dbutils.ResultSetHandler --- 結(jié)果集封裝器
- org.apache.commons.dbutils.DbUtils --- 工具類
學(xué)習(xí)重點(diǎn):多看看API澳迫,多看看官網(wǎng)的example局齿!
2、DbUtils類
DbUtils :提供如加載驅(qū)動(dòng)橄登、關(guān)閉連接抓歼、事務(wù)提交、回滾等常規(guī)工作的工具類拢锹,里面的所有方法都是靜態(tài)的谣妻。主要方法如下:
-
DbUtils類提供了三個(gè)重載的關(guān)閉方法。這些方法檢查所提供的參數(shù)是不是NULL卒稳,如果不是的話蹋半,它們就關(guān)閉Connection、Statement和ResultSet充坑。
public static void close(…) throws java.sql.SQLException
-
這一類"quietly"方法不僅能在Connection减江、Statement和ResultSet為NULL情況下避免關(guān)閉,還能隱藏一些在程序中拋出的SQLException捻爷。
public static void closeQuietly(…)
-
用來提交連接辈灼,然后關(guān)閉連接,并且在關(guān)閉連接時(shí)不拋出SQL異常也榄。
public static void commitAndCloseQuietly(Connection conn)
-
裝載并注冊(cè)JDBC驅(qū)動(dòng)程序巡莹,如果成功就返回true。使用該方法甜紫,你不需要捕捉這個(gè)異常ClassNotFoundException降宅。
public static boolean loadDriver(java.lang.String driverClassName)
3、QueryRunner類
該類簡(jiǎn)單化了SQL查詢囚霸,它與ResultSetHandler組合在一起使用可以完成大部分的數(shù)據(jù)庫操作钉鸯,能夠大大減少編碼量。
-
QueryRunner類提供了兩個(gè)構(gòu)造方法:
默認(rèn)的構(gòu)造方法:QueryRunner()
-
需要一個(gè) javax.sql.DataSource 來作參數(shù)的構(gòu)造方法:QueryRunner(DataSource ds)
注意:構(gòu)造器需要傳入DataSource參數(shù)邮辽,所以必須要用到連接池唠雕,關(guān)于JDBC連接池可參考我之前的一篇文章:《JDBC進(jìn)階——連接池》。在那篇文章中的JDBCUtils類中沒有相應(yīng)的方法來獲得DataSource對(duì)象吨述,所以應(yīng)該在JDBCUtils類中加入如下代碼:
// 返回?cái)?shù)據(jù)庫連接池 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,將數(shù)據(jù)按要求轉(zhuǎn)換為另一種形式揣云。
-
ResultSetHandler 接口提供了一個(gè)單獨(dú)的方法:
Object handle(ResultSet rs){}
-
ResultSetHandler 接口的實(shí)現(xiàn)類(構(gòu)造方法不唯一捕儒,在這里只用最常見的構(gòu)造方法):
ArrayHandler():把結(jié)果集中的第一行數(shù)據(jù)轉(zhuǎn)成對(duì)象數(shù)組(存入Object[])。
ArrayListHandler():把結(jié)果集中的每一行數(shù)據(jù)都轉(zhuǎn)成一個(gè)對(duì)象數(shù)組,再存放到List中刘莹。
BeanHandler(Class
<T>
type):將結(jié)果集中的第一行數(shù)據(jù)封裝到一個(gè)對(duì)應(yīng)的JavaBean實(shí)例中阎毅。-
BeanListHandler(Class
<T>
type):將結(jié)果集中的每一行數(shù)據(jù)都封裝到一個(gè)對(duì)應(yīng)的JavaBean實(shí)例中,存放到List里点弯。Parameters:
type - The Class that objects returned from handle() are created from.
ColumnListHandler(String columnName/int columnIndex):將結(jié)果集中某一列的數(shù)據(jù)存放到List中扇调。
MapHandler():將結(jié)果集中的第一行數(shù)據(jù)封裝到一個(gè)Map里,key是列名抢肛,value就是對(duì)應(yīng)的值狼钮。
MapListHandler():將結(jié)果集中的每一行數(shù)據(jù)都封裝到一個(gè)Map里,然后再將所有的Map存放到List中捡絮。
KeyedHandler(String columnName):將結(jié)果集每一行數(shù)據(jù)保存到一個(gè)“小”map中,key為列名熬芜,value該列的值,再將所有“小”map對(duì)象保存到一個(gè)“大”map中 福稳, “大”map中的key為指定列涎拉,value為“小”map對(duì)象
ScalarHandler(int columnIndex):通常用來保存只有一行一列的結(jié)果集。
注意: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包加入到項(xiàng)目工程的build path中略板。
-
對(duì)于CUD毁枯,有兩種不同的情況:
-
情況一:
如果使用 QueryRunner(DataSource ds) 構(gòu)造器創(chuàng)建QueryRunner對(duì)象量蕊,需要使用連接池兢交,如DBCP、C3P0等等致燥,數(shù)據(jù)庫事務(wù)交給DBUtils框架進(jìn)行管理 ---- 默認(rèn)情況下每條SQL語句單獨(dú)一個(gè)事務(wù)瓤檐。
-
在這種情況下赂韵,使用如下方法:
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 { // 第一步 創(chuàng)建QueryRunner對(duì)象 QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); // 第二步 準(zhǔn)備方法參數(shù) String sql = "insert into users values(null,?,?,?)"; Object[] param = { "小麗", "qwe", "xiaoli@itcast.cn" }; // 第三步 調(diào)用 query / update queryRunner.update(sql, param); }
-
-
情況二:
如果使用 QueryRunner() 構(gòu)造器創(chuàng)建QueryRunner對(duì)象 ,需要自己管理事務(wù)挠蛉,因?yàn)榭蚣軟]有連接池?zé)o法獲得數(shù)據(jù)庫連接祭示。
-
在這種情況下,要使用傳入Connection對(duì)象參數(shù)的方法:
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) update(Connection conn, String sql, Object... params)
-
demo:
// 事務(wù)控制 @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的構(gòu)造器谴古,默認(rèn)每條SQL語句一個(gè)單獨(dú)事務(wù)质涛,而在這里要自己管理業(yè)務(wù),所以不合適掰担! // QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); QueryRunner queryRunner = new QueryRunner();// 不要傳遞連接池 --- 手動(dòng)事務(wù)管理 Connection conn = JDBCUtils.getConnection(); conn.setAutoCommit(false); try { queryRunner.update(conn, sql1, money, outAccount); // 注意要傳入Connection對(duì)象的方法 // int d = 1 / 0; queryRunner.update(conn, sql2, money, inAccount); System.out.println("事務(wù)提交汇陆!"); DbUtils.commitAndCloseQuietly(conn); } catch (Exception e) { System.out.println("事務(wù)回滾!"); DbUtils.rollbackAndCloseQuietly(conn); e.printStackTrace(); } }
-
-
-
對(duì)于R带饱,需要用到ResultSetHandler接口毡代,該接口有9大實(shí)現(xiàn)類阅羹,
public class ResultSetHandlerTest { // ScalarHandler 通常用于保存只有一行一列的結(jié)果集,例如分組函數(shù) @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)); // 得到結(jié)果集的第1列 System.out.println(count); } // KeyedHandler 將結(jié)果集每一行數(shù)據(jù)保存到一個(gè)“小”map中,key為列名教寂,value該列的值捏鱼,再將所有“小”map對(duì)象保存到一個(gè)“大”map中 , “大”map中的key為指定列酪耕,value為“小”map對(duì)象 @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 將結(jié)果集每一行數(shù)據(jù)保存到map中导梆,key列名 value該列的值 ---- 再將所有map對(duì)象保存到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 將結(jié)果集第一行數(shù)據(jù)封裝到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 獲得結(jié)果集的某一列猿诸,將該列的所有值存入List<Object>中 @Test public void demo5() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 因?yàn)槊苛蓄愋投疾灰粯踊楸唬杂肔ist<Object>存儲(chǔ) // List<Object> list = queryRunner.query(sql, // new ColumnListHandler("name")); // 得到表列名為name的列 List<Object> list = queryRunner.query(sql, new ColumnListHandler(2)); // 得到結(jié)果集的第2列 System.out.println(list); } // BeanListHander 將結(jié)果集每一條數(shù)據(jù),轉(zhuǎn)為JavaBean對(duì)象梳虽,再保存到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 將結(jié)果集第一行數(shù)據(jù)封裝到JavaBean對(duì)象中 @Test public void demo3() throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 傳入 Account.class字節(jié)碼文件:為了在方法中 通過反射構(gòu)造Account對(duì)象 // 使用BeanHandler注意事項(xiàng) :數(shù)據(jù)庫中的表列名 與 Bean類中屬性 名稱一致V沸尽!窜觉! 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 將結(jié)果集每一行數(shù)據(jù)保存到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 將結(jié)果集第一行數(shù)據(jù)保存到Object[]中 @Test public void demo1() throws SQLException { // 使用DBUtils QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from account"; // 對(duì)象數(shù)組存儲(chǔ)rs第一行數(shù)據(jù)的所有列 Object[] values = queryRunner.query(sql, new ArrayHandler()); System.out.println(Arrays.toString(values)); } }
JDBC文集:
Java 與數(shù)據(jù)庫的橋梁——JDBC:http://www.reibang.com/p/c0acbd18794c
JDBC 進(jìn)階——連接池:http://www.reibang.com/p/ad0ff2961597
JDBC 進(jìn)階——元數(shù)據(jù):http://www.reibang.com/p/36d5d76342f1
JDBC框架——DBUtils:http://www.reibang.com/p/10241754cdd7