JDBC框架——DBUtils

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容