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。

      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、使用步驟

  1. 將DBUtils的jar包加入到項目工程的build path中。

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

  1. Java 與數據庫的橋梁——JDBC:http://www.lxweimin.com/p/c0acbd18794c

  2. JDBC 進階——連接池:http://www.lxweimin.com/p/ad0ff2961597

  3. JDBC 進階——元數據:http://www.lxweimin.com/p/36d5d76342f1

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • JDBC框架——DBUtils 本文包括: 1、DBUtils簡介 2、DbUtils類 3、QueryRunne...
    加油小杜閱讀 915評論 0 1
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,767評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,973評論 19 139
  • 01. 回憶綿長,卻再無羈絆。 2014年8月1日,我在大英博物館門口跟一位來自澳門的小帥哥聊完hello kit...
    Cressida小麥閱讀 359評論 0 0
  • 婷二和毛跳的遇見起源一次不大不小的打劫。抓著口水橫流的棒棒糖,婷二覺得人生真是太滿足了,她不笨就是腦子轉的比...
    雙葉彎閱讀 231評論 0 0