posts - 11,  comments - 41,  trackbacks - 0

          雖然現在出現了很多ORM框架,可是還是有很多朋友也許還在使用JDBC,就像我現在一樣,除了學習的時候在使用Hibernate、Spring類似這些優秀的框架,工作時一直都在使用JDBC。本文就簡單介紹一下利用Jakarta Commons旗下beanutils、dbutils簡化JDBC數據庫操作,以拋磚引玉,希望對像我一樣在使用JDBC的朋友有所幫助。

              下面就分兩部分簡單介紹beanutils、dbutils在基于JDBC API數據庫存取操作中的運用。第一部分顯介紹beanutils在JDBC數據庫存取操作中的運用,第二部分介紹dbutils在JDBC數據庫存取操作中的運用,最后看看他們的優缺點,談談本人在項目運用過程中對他們的一點心得體會,僅供參考,其中有錯誤的地方希望大蝦不吝賜教,大家多多交流共同進步。

          一、Jakarta Commons beanutils

                 Beanutils是操作Bean的銳利武器,其提過的BeanUtils工具類可以簡單方便的讀取或設置Bean的屬性,利用Dyna系列,還可以在運行期創建Bean,符合懶人的習慣,正如LazyDynaBean,LazyDynaClass一樣,呵呵。這些用法已經有很多文章提及,也可以參考apache的官方文檔。

          對于直接利用JDBC API訪問數據庫時(這里針對的是返回結果集ResultSet的查詢select),大多數都是采用兩種方式,一種是取出返回的結果集的數據存于Map中,另一種方式是Bean里。針對第二種方式,Beanutils里提供了ResultSetDynaClass結合DynaBean以及RowSetDynaClass結合DynaBean來簡化操作。下面用以個簡單的例子展示一下beanutils的這兩個類在JDBC數據庫操作中的運用。

          請在本機建立數據庫publish,我用的是MySQL,在publish數據庫中建立表book,腳本如下:
          CREATE TABLE book(
            id int(11) NOT NULL auto_increment,
            title varchar(50) character set latin1 NOT NULL,
            authors varchar(50) character set latin1 default NULL, 
            PRIMARY KEY  (id)


                   然后用你喜歡的編輯器建立一個類BeanutilsJDBCTest,我們先用ResultSetDynaClass來處理,然后再用RowSetDynaClass來實現同樣的類,之后看看他們之間有什么不同,用ResultSetDynaClass處理的源代碼如下所示:

          package cn.qtone.test;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Statement;
          import java.util.Iterator; 
          import org.apache.commons.beanutils.DynaBean;
          import org.apache.commons.beanutils.PropertyUtils;
          import org.apache.commons.beanutils.ResultSetDynaClass; 

          public class BeanutilsJDBCTest{
                 public static void main(String[] args) {
                        Connection con = null;
                        Statement st = null;
                        ResultSet rs = null;
                        try {
                               Class.forName("com.mysql.jdbc.Driver");

                               String url = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";

                               con = DriverManager.getConnection(url, "root", "hyys");

                               st = con.createStatement();

                               rs = st.executeQuery("select * from book");

                               ResultSetDynaClass rsDynaClass = new ResultSetDynaClass(rs);

                               Iterator itr = rsDynaClass.iterator();

                               System.out.println("title-------------authors");

                               while (itr.hasNext()) {
                                      DynaBean dBean = (DynaBean) itr.next();
                                      System.out.println(PropertyUtils.getSimpleProperty(dBean,"title")
                                                    + "-------------"+ PropertyUtils.getSimpleProperty(dBean, "authors"));

                               }
                        } catch (Exception e) {
                               e.printStackTrace();
                        } finally {
                               try {
                                      if (rs != null) {
                                             rs.close();
                                      }
                                      if (st != null) {
                                             st.close();
                                      }
                                      if (con != null) {
                                             con.close();
                                      }
                               } catch (Exception e) {
                                      e.printStackTrace();
                               }
                        }
                 }




          用RowSetDynaClass處理的源代碼如下所示: 


          package cn.qtone.test; 

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Statement;
          import java.util.Iterator;
          import java.util.List; 
          import org.apache.commons.beanutils.DynaBean;
          import org.apache.commons.beanutils.PropertyUtils;
          import org.apache.commons.beanutils.RowSetDynaClass; 

          public class BeanutilsJDBCTest{
                 public static void main(String[] args) {
                        List rsDynaClass = rsTest();

                        System.out.println("title ------------- authors ");

                        Iterator itr = rsDynaClass.iterator();

                        while (itr.hasNext()) {

                               DynaBean dBean = (DynaBean) itr.next();

                               try {
                                      System.out.println(PropertyUtils.getSimpleProperty(dBean,"name")
                                                    + "-------------"+ PropertyUtils.getSimpleProperty(dBean, "mobile"));

                               } catch (Exception e) {
                                      // TODO 自動生成 catch 塊
                                      e.printStackTrace();
                               }
                        }
                 } 

                 private static List rsTest() {

                        Connection con = null;
                        Statement st = null;
                        ResultSet rs = null;

                        try {
                               Class.forName("com.mysql.jdbc.Driver");

                               String url = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";

                               con = DriverManager.getConnection(url, "root", "hyys");

                               st = con.createStatement();

                               rs = st.executeQuery("select * from book");

                               RowSetDynaClass rsdc = new RowSetDynaClass(rs);

                               return rsdc.getRows();

                        } catch (Exception e) {
                               e.printStackTrace();
                        } finally {
                               try {
                                      if (rs != null) {
                                             rs.close();
                                      }
                                      if (st != null) {
                                             st.close();
                                      }
                                      if (con != null) {
                                             con.close();
                                      }
                               } catch (Exception e) {
                                      e.printStackTrace();
                               }
                        }

                        return null;
                 }



          這兩個方法輸出的結果應該是一樣的。但是很顯然第二種方式比第一種方式要好,它把數據訪問部分抽取出來放到一個方法中,顯得簡單清晰。

          其實在利用ResultSetDynaClass時,必須在ResultSet等數據庫資源關閉之前,處理好那些數據,你不能在資源關閉之后使用DynaBean,否則就會拋出異常,異常就是說不能在ResultSet之后存取數據(具體的異常名我也忘了),當然你也可以采用以前的方式一個一個的把數據放到Map里,如果你一定要那樣做,建議還是別用Beanutils,因為這沒帶給你什么好處。總之利用ResultSetDynaClass你的程序的擴展性非常部好。

          從第二中方式可以看出,利用RowSetDynaClass可以很好的解決上述ResultSetDynaClass遇到的問題,RowSetDynaClass的getRows()方法,把每一行封裝在一個DynaBean對象里,然后,把說有的行放到一個List里,之后你就可以對返回的List里的每一個DynaBean進行處理,此外對于DynaBean你還可以采用標準的get/set方式處理,當然你也可以用PropertyUtils. getSimpleProperty(Object bean, String name)進行處理。

          從上面的分析中,你應該可以決定你應該使用ResultSetDynaClass還是RowSetDynaClass了。





          未完待續……

          =============================

          二、Jakarta Commons dbutils:
              用JDBC API時最令人討厭的就是異常處理,也很煩瑣,而且很容易出錯,本人曾考慮過利用模板進行處理,后來看到了dbutils,之后就采用那個dbutils,采用模板的方式各位朋友可以參考Spring,Spring的JdbcTemplate不靈活而強大,呵呵,說句閑話,實在太佩服Rod Johnson了,Rod Johnson真的很令人尊敬。
              Dbutils的QueryRunner把大多數與關閉資源相關的封裝起來,另外,你也可以使用DbUtils進行關閉,當然DbUtils提供的功能當然不止這些,它提過了幾個常用的靜態方法,除了上述的關閉資源外,DbUtils. commitAndClose(Connection conn)還提供事務提及等操作。
          還是以一個例子來說說吧,畢竟我不是搞業務的,小嘴巴吧嗒吧噠不起來啊,呵呵。
              為了和采用Beanutils更好的進行對比,這個例子還是實現同樣的功能,數據庫同樣采用前一篇文章中提到的publish。
          同樣的,用你喜歡的編輯器建立一個類DbutilsJDBCTest,示例代碼如下所示:
          package cn.qtone.test;
          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.SQLException;
          import java.util.List;
          import java.util.Map;
          import org.apache.commons.dbutils.DbUtils;
          import org.apache.commons.dbutils.QueryRunner;
          import org.apache.commons.dbutils.handlers.MapListHandler;
          public class DbutilsJDBCTest{
              public static void main(String[] args) {
                  Connection conn = null;
                  String jdbcURL = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";
                  String jdbcDriver = "com.mysql.jdbc.Driver";
                  try {
                      DbUtils.loadDriver(jdbcDriver);
                      // Username "root". Password "root"
                      conn = DriverManager.getConnection(jdbcURL, "root", "root");
                      QueryRunner qRunner = new QueryRunner();
                      System.out.println("***Using MapListHandler***");
                      //以下部分代碼采用Map存儲方式,可以采用Bean的方式代替進行處理
                      List lMap = (List) qRunner.query(conn,
                              "select title,authors  from books", new MapListHandler());
                      //以下是處理代碼,可以抽取出來
          System.out.println("title ------------- authors ");
                          for (int i = 0; i < lMap.size(); i++) {
                                  Map vals = (Map) lMap.get(i);
                                  System.out.println(vals.get("title")+"-------------"+ vals.get("authors"));
                          }
                  } catch (SQLException ex) {
                      ex.printStackTrace();
                  } finally {
                      DbUtils.closeQuietly(conn);
                  }
              }
          }

          怎么樣?是不是比采用Beanutils的ResultSetDynaTrial和RowSetDynaClass好多了?采用Beanutils令人難纏的是關閉那些資源以及處理那些異常,而這里采用Dbutils顯然代碼量減少了很多。
          上例在處理結果集時,它把數據庫中的每一行映射成一個Map,其中列名作為Key,該列對應的值作為Value存放,查詢的所有的數據一起放在一個List里,然后進行處理,當然,一個更明智的處理是直接返回List然后再單獨進行處理。
          事實上上例返回的結果集中的每一行不必放在一個Map里,你可以放在一個Bean里,當然如果你真的很懶,你也可以使用Beanutils的LazyDynaClass和LazyDynaBean,不過也許沒有必要那么做,至于原因請看下文。

          如果使用Bean而不是用Map,那么,你也許需要建立一個Bean,如下:
          package cn.qtone.test;
          public class Book {
              public int id;
              public String title;
              public String authors ;
              public StudentBean() {
              }
              public String getAuthors() {
                  return authors;
              }
              public void setAuthors(String authors) {
                  this.authors = authors;
              }
              public int getId() {
                  return id;
              }
              public void setId(int id) {
                  this.id = id;
              }
              public String getTitle() {
                  return title;
              }
              public void setTitle(String title) {
                  this.title = title;
              }
          }

          然后簡單修改一下DbutilsJDBCTest 中的部分代碼即可,代替之后的源代碼如下:

          package cn.qtone.test;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.SQLException;
          import java.util.List;
          import java.util.Map;
          import org.apache.commons.dbutils.DbUtils;
          import org.apache.commons.dbutils.QueryRunner;
          import org.apache.commons.dbutils.handlers.BeanListHandler;

          public class DbutilsJDBCTest{
              public static void main(String[] args) {
                  Connection conn = null;
                  String jdbcURL = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";
                  String jdbcDriver = "com.mysql.jdbc.Driver";
                  try {
                      DbUtils.loadDriver(jdbcDriver);
                      // Username "root". Password "root"
                      conn = DriverManager.getConnection(jdbcURL, "root", "root");
                      QueryRunner qRunner = new QueryRunner();
                      System.out.println("***Using BeanListHandler ***");
                      //以下部分代碼采用Map存儲方式,可以采用Bean的方式代替進行處理
          List lBeans = (List) qRunner.query(conn," select title,authors from books ", new BeanListHandler(Book.class));
              //以下是處理代碼,可以抽取出來
          System.out.println("title ------------- authors ");
              for (int i = 0; i < lBeans.size(); i++) {
                      Book vals = (Book) lBeans.get(i);    
                    System.out.println(vals.getTitle ()+"-------------"+ vals. getAuthors ());
                          }
                  } catch (SQLException ex) {
                      ex.printStackTrace();
                  } finally {
                      DbUtils.closeQuietly(conn);
                  }
              }
          }
              這兩種法輸出的結果應該是一樣的。兩種處理方式都差不多,但我更愿意采用第一種,因為第一種少寫一個bean,而且我測試過采用Map的方式即第一種方式性能要好的多,采用Bean性能比較低可能是因為采用反射的緣故,采用反射的東東性能和不采用反射的還是有點差距。也是這個原因,不推薦采用LazyDynaClass和LazyDynaBean,因為采用這二者是在運行期動態創建Bean類和Bean屬性,然后再創建Bean對象的,其性能可想而知了(不過我沒有測試過啊,所以我說這個話可說是沒有根據的,感興趣的朋友自己測試一下,記得告訴我結果哦,呵呵),除了MapListHandler以及BeanListHandler之外,DButils還提供了其他的Handler,如果這些不能滿足你的需求,你也可以自己實現一個Handler。
              最后,也是最大的體會,也許是最大的收獲吧,那就是:對于每一個項目,在根據每一個需求獲取相應解決方案時,先尋找開源組件,看是否已經有滿足某些功能需求的開源組件,如果沒有,再考慮自主開發或者向第三方購買,否則盡量采用開源組件.
              請盡量享用開源的魅力,盡情的擁抱開源吧。

          posted on 2008-04-24 16:39 GoKu 閱讀(778) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          <2008年4月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          常用鏈接

          留言簿(1)

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 仁布县| 贞丰县| 静海县| 台山市| 徐闻县| 建始县| 赞皇县| 新田县| 滦南县| 永泰县| 龙山县| 仲巴县| 平罗县| 呼和浩特市| 徐州市| 广饶县| 江油市| 广安市| 万宁市| 南部县| 金乡县| 永吉县| 赤峰市| 新营市| 江华| 长垣县| 武宣县| 苏州市| 宜良县| 进贤县| 乌兰县| 茶陵县| 宝清县| 通渭县| 溧阳市| 洪江市| 渝中区| 武乡县| 泰宁县| 兴文县| 防城港市|