JDBC框架——DBUtils

本文包括:

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 --- 工具類
  • 地址:http://commons.apache.org/proper/commons-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、使用步驟

  1. 將DBUtils的jar包加入到項(xiàng)目工程的build path中略板。

  2. 對(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();
              }
          }
        
  3. 對(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文集:

  1. Java 與數(shù)據(jù)庫的橋梁——JDBC:http://www.reibang.com/p/c0acbd18794c

  2. JDBC 進(jìn)階——連接池:http://www.reibang.com/p/ad0ff2961597

  3. JDBC 進(jìn)階——元數(shù)據(jù):http://www.reibang.com/p/36d5d76342f1

  4. JDBC框架——DBUtils:http://www.reibang.com/p/10241754cdd7

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谷炸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子禀挫,更是在濱河造成了極大的恐慌旬陡,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件语婴,死亡現(xiàn)場(chǎng)離奇詭異描孟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)砰左,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門匿醒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缠导,你說我怎么就攤上這事廉羔。” “怎么了僻造?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵憋他,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我髓削,道長(zhǎng)举瑰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任蔬螟,我火速辦了婚禮此迅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己耸序,他們只是感情好忍些,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坎怪,像睡著了一般罢坝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搅窿,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天嘁酿,我揣著相機(jī)與錄音,去河邊找鬼男应。 笑死闹司,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沐飘。 我是一名探鬼主播游桩,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼耐朴!你這毒婦竟也來了借卧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤筛峭,失蹤者是張志新(化名)和其女友劉穎铐刘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體影晓,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镰吵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俯艰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捡遍。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竹握,靈堂內(nèi)的尸體忽然破棺而出画株,到底是詐尸還是另有隱情,我是刑警寧澤啦辐,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布谓传,位于F島的核電站,受9級(jí)特大地震影響芹关,放射性物質(zhì)發(fā)生泄漏续挟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一侥衬、第九天 我趴在偏房一處隱蔽的房頂上張望诗祸。 院中可真熱鬧跑芳,春花似錦、人聲如沸直颅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽功偿。三九已至盆佣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間械荷,已是汗流浹背共耍。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吨瞎,地道東北人痹兜。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像关拒,于是被迫代替她去往敵國和親佃蚜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庸娱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • JDBC框架——DBUtils 本文包括: 1着绊、DBUtils簡(jiǎn)介 2、DbUtils類 3熟尉、QueryRunne...
    加油小杜閱讀 885評(píng)論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法归露,類相關(guān)的語法,內(nèi)部類的語法斤儿,繼承相關(guān)的語法剧包,異常的語法,線程的語...
    子非魚_t_閱讀 31,623評(píng)論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理往果,服務(wù)發(fā)現(xiàn)疆液,斷路器,智...
    卡卡羅2017閱讀 134,652評(píng)論 18 139
  • 01. 回憶綿長(zhǎng),卻再無羈絆肮之。 2014年8月1日掉缺,我在大英博物館門口跟一位來自澳門的小帥哥聊完hello kit...
    Cressida小麥閱讀 338評(píng)論 0 0
  • 婷二和毛跳的遇見起源一次不大不小的打劫。抓著口水橫流的棒棒糖戈擒,婷二覺得人生真是太滿足了眶明,她不笨就是腦子轉(zhuǎn)的比...
    雙葉彎閱讀 217評(píng)論 0 0