JDBC框架——DBUtils
本文包括:
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 --- 工具類
地址:http://commons.apache.org/proper/commons-dbutils/
學習重點:多看看API,多看看官網的example!
2、DbUtils類
DbUtils :提供如加載驅動、關閉連接、事務提交、回滾等常規工作的工具類,里面的所有方法都是靜態的。主要方法如下:
DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉Connection、Statement和ResultSet。
publicstaticvoidclose(…) throws java.sql.SQLException
這一類"quietly"方法不僅能在Connection、Statement和ResultSet為NULL情況下避免關閉,還能隱藏一些在程序中拋出的SQLException。
publicstaticvoidcloseQuietly(…)
用來提交連接,然后關閉連接,并且在關閉連接時不拋出SQL異常。
publicstaticvoidcommitAndCloseQuietly(Connection conn)
裝載并注冊JDBC驅動程序,如果成功就返回true。使用該方法,你不需要捕捉這個異常ClassNotFoundException。
publicstaticbooleanloadDriver(java.lang.StringdriverClassName)
3、QueryRunner類
該類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的數據庫操作,能夠大大減少編碼量。
QueryRunner類提供了兩個構造方法:
默認的構造方法:QueryRunner()
需要一個 javax.sql.DataSource 來作參數的構造方法:QueryRunner(DataSource ds)
注意:構造器需要傳入DataSource參數,所以必須要用到連接池,關于JDBC連接池可參考我之前的一篇文章:《JDBC進階——連接池》。在那篇文章中的JDBCUtils類中沒有相應的方法來獲得DataSource對象,所以應該在JDBCUtils類中加入如下代碼:
// 返回數據庫連接池publicstaticDataSourcegetDataSource(){returndataSource;}
常用方法(分為兩種情況):
批處理
batch(Connection conn,Stringsql,Object[][] params)// 傳遞連接批處理batch(Stringsql,Object[][] params)// 不傳遞連接批處理
查詢操作
publicObjectquery(Connection conn,Stringsql, ResultSetHandler rsh,Object... params)publicObjectquery(Stringsql, ResultSetHandler rsh,Object... params)
更新操作
public intupdate(Connectionconn,Stringsql, Object... params)publicintupdate(Stringsql, Object... params)
4、ResultSetHandler接口
該接口用于處理 java.sql.ResultSet,將數據按要求轉換為另一種形式。
ResultSetHandler 接口提供了一個單獨的方法:
Objecthandle(ResultSetrs){}
ResultSetHandler 接口的實現類(構造方法不唯一,在這里只用最常見的構造方法):
ArrayHandler():把結果集中的第一行數據轉成對象數組(存入Object[])。
ArrayListHandler():把結果集中的每一行數據都轉成一個對象數組,再存放到List中。
BeanHandler(Classtype):將結果集中的第一行數據封裝到一個對應的JavaBean實例中。
BeanListHandler(Classtype):將結果集中的每一行數據都封裝到一個對應的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(Stringsql, Object[][]params)? query(Stringsql, ResultSetHandlerrsh, Object...params)? update(Stringsql, Object...params)
demo:
@TestpublicvoidtestDelete()throwsSQLException{? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());? ? ? String sql ="delete from users where id = ?";? ? ? queryRunner.update(sql,3);? }@TestpublicvoidtestUpdate()throwsSQLException{? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());? ? ? String sql ="update users set password = ? where username = ?";? ? ? Object[] param = {"nihao","小明"};? ? ? queryRunner.update(sql, param);? }@TestpublicvoidtestInsert()throwsSQLException{// 第一步 創建QueryRunner對象QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());// 第二步 準備方法參數String sql ="insert into users values(null,?,?,?)";? ? ? Object[] param = {"小麗","qwe","xiaoli@itcast.cn"};// 第三步 調用 query / updatequeryRunner.update(sql, param);? }
情況二:
如果使用 QueryRunner() 構造器創建QueryRunner對象 ,需要自己管理事務,因為框架沒有連接池無法獲得數據庫連接。
在這種情況下,要使用傳入Connection對象參數的方法:
query(Connection conn,Stringsql, ResultSetHandler rsh, Object...params)? update(Connection conn,Stringsql, Object...params)
demo:
// 事務控制@TestpublicvoidtestTransfer()throwsSQLException {doublemoney =100;StringoutAccount ="aaa";StringinAccount ="bbb";Stringsql1 ="update account set money = money - ? where name= ?";Stringsql2 ="update account set money = money + ? where name= ?";// 傳入DataSource的構造器,默認每條SQL語句一個單獨事務,而在這里要自己管理業務,所以不合適!// QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());QueryRunner queryRunner =newQueryRunner();// 不要傳遞連接池 --- 手動事務管理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大實現類,
publicclass ResultSetHandlerTest {// ScalarHandler 通常用于保存只有一行一列的結果集,例如分組函數@Testpublicvoiddemo9()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select count(*) from account";longcount = (Long) queryRunner.query(sql,newScalarHandler(1));// 得到結果集的第1列System.out.println(count);? ? }// KeyedHandler 將結果集每一行數據保存到一個“小”map中,key為列名,value該列的值,再將所有“小”map對象保存到一個“大”map中 , “大”map中的key為指定列,value為“小”map對象@Testpublicvoiddemo8()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";? ? ? ? Map>map= queryRunner.query(sql,newKeyedHandler("id"));? ? ? ? System.out.println(map);? ? }// MapListHandler 將結果集每一行數據保存到map中,key列名 value該列的值 ---- 再將所有map對象保存到List集合中@Testpublicvoiddemo7()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";? ? ? ? List> list = queryRunner.query(sql,newMapListHandler());for(Mapmap: list) {? ? ? ? ? ? System.out.println(map);? ? ? ? }? ? }// MapHander 將結果集第一行數據封裝到Map集合中,key是列名,value為該列的值@Testpublicvoiddemo6()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";? ? ? ? Mapmap= queryRunner.query(sql,newMapHandler());// 列名為String類型,該列的值為Object類型System.out.println(map);? ? }// ColumnListHandler 獲得結果集的某一列,將該列的所有值存入List中@Testpublicvoiddemo5()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 因為每列類型都不一樣,所以用List存儲// List list = queryRunner.query(sql,// new ColumnListHandler("name")); // 得到表列名為name的列List list = queryRunner.query(sql,newColumnListHandler(2));// 得到結果集的第2列System.out.println(list);? ? }// BeanListHander 將結果集每一條數據,轉為JavaBean對象,再保存到list集合中@Testpublicvoiddemo4()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";? ? ? ? List accounts = queryRunner.query(sql,newBeanListHandler(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對象中@Testpublicvoiddemo3()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 傳入 Account.class字節碼文件:為了在方法中 通過反射構造Account對象// 使用BeanHandler注意事項 :數據庫中的表列名 與 Bean類中屬性 名稱一致!!!Account account = queryRunner.query(sql,newBeanHandler(? ? ? ? ? ? ? ? Account.class));? ? ? ? System.out.println(account.getId());? ? ? ? System.out.println(account.getName());? ? ? ? System.out.println(account.getMoney());? ? }// ArrayListHandler 將結果集每一行數據保存到List中@Testpublicvoiddemo2()throwsSQLException {? ? ? ? QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";? ? ? ? List list = queryRunner.query(sql,newArrayListHandler());for(Object[] objects : list) {? ? ? ? ? ? System.out.println(Arrays.toString(objects));? ? ? ? }? ? }// ArrayHandler 將結果集第一行數據保存到Object[]中@Testpublicvoiddemo1()throwsSQLException {// 使用DBUtilsQueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 對象數組存儲rs第一行數據的所有列Object[] values = queryRunner.query(sql,newArrayHandler());? ? ? ? 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