狂奔 lion

          自強不息

          [譯]JDBC4.0具有哪些新特性?

          Java SE 6 所提供的諸多新特性和改進中,值得一提的是為 Java 程序提供數據庫訪問機制的 JDBC 版本升級到了 4.0, 這個以 JSR-221 為代號的版本 , 提供了更加便利的代碼編寫機制及柔性 , 并且支持更多的數據類型 . 在本文中,我們將從編碼的易用性及柔性的角度探討 JDBC 4.0 所帶來的新特性及改進。
          JDBC 4.0 的新特性

          JDBC 4.0 文檔列舉了 20 個改進及新特性 , 大小不等 . 本文無法做到盡述其詳 , 為此筆者根據其功能特點及應用領域將其分為下述四類:

          1.     驅動及連接管理

          2.     異常處理

          3.     數據類型支持

          4.     API 的變化

          下面按照上述四類展開詳述:

          驅動及連接管理

          驅動及連接的使用和結果集管理 JDBC 的很多地方都發生了顯著的變化

          連接數據庫變得更加容易

          如果您曾經有過 JDBC 開發的經驗 , 那么我確信您還保存著一份建立數據庫連接所必須的工作列表 . 而列表中的第一項即加載一個合適的驅動程序 . 您是否想過這個步驟應該被改進呢 ? 在此版 JDBC 中做到了 . 您不必再顯式地加載 Class.forName . 當您的程序首次試圖連接數據庫時 , DriverManager 自動加載驅動到當前應用的 CLASSPATH . 這是 JDBC 的一個比較大的改動 .

          盡管 DriverManager 現在可以自動地加載驅動 , 建立一個 DataSource 對象 仍是獲取連接的推薦的方法 . 因為可以在配置中將數據源指向不同的數據庫, DataSource 更具透明性和靈活性。 這樣就可以訪問另一個數據庫實例不需更改現有的任意一行代碼 , 甚至數據庫的驅動完全不同也沒有關系 .

          ResultSet 的使用變得更為靈活

          ResultSet 接口的層次結構當前為編程的靈活性提供了一些新的機制 . RowSet 子接口滾動、可提交并可離線編輯的 ResultSet . WebRowSet 子接口提供了從數據庫表中獲取數據 , 并將其序列化為 XML 文檔 , 抑或是將 XML 解析成 result set 的能力 . 盡管上個版本的 JDBC 也提供了 RowSet 接口層次 ,當前的版本對于 SQLXML 數據類型支持得更好 ( 稍后討論 ) ,這些特性是的 JDBC 編程更加容易且具靈活性 .

          提供了更多的 API

          本版 JDBC 提供了更多的 API 以實現訪問 SQL:2003 具備的新特性 . 此外 , 為了更好的操縱修改數據, JDBC 也增添了許多的方法。 .

          現在我們來看一些代碼并討論下面 Example1 類的輸出結果 . 它將連接嵌入式的 Apache Derby 數據庫并在控制臺上顯示輸出結果 . 盡管 JDBC 4.0 已推出幾個月了 , 筆者發現只有 Apache Derby 提供了支持 JDBC 4.0 規范的驅動 ( 截至 2007 3 ). 本文的所有例子均用 JDK 1.6 Apache Derby 數據庫 10.2.2.0 開發 .

           

          public class Example1 {

            public static void main(String[] args) {

              ...

              String dbName = "example1";

              String tableName = "stu1";

              ds = new EmbeddedDataSource40();

              ds.setDatabaseName(dbName);

              String connectionURL = "jdbc:derby:"+dbName+";create=true";

              try {

                con = ds.getConnection();

                stmt = con.createStatement();

                rs = stmt.executeQuery("select * from "+tableName);

                int colCount= rs.getMetaData().getColumnCount();

                for (int j=0; j< colCount; j++){

                  System.out.print(rs.getMetaData().getColumnName(j+1)

                    + "\t");

                }

                while (rs.next()) {

                  System.out.print("\n");

                  for (int i = 0; i < colCount; i++) {

                   System.out.print(rs.getString(i + 1) + "\t");

                  }

                }

               } catch (SQLException e) {

                     e.printStackTrace();

                   }

               finally{

                //close connections

               }

             }

          }

           

          如果在 example1 數據庫的 stu1 表中有數據的話 , 編譯并運行 Example1.java 將在控制臺獲得以下輸出:

           

          ID    NAME            COURSE

          1001  John Doe        Statistics    

          1002  Jack McDonalds  Linear Algebra

           

          如果想看 DriverManager 如何自動加載 JDBC 驅動 , 可以將 Example1 中的: con=ds.getConnection() 替換為: con=DriverManager.getConnection(connectionURL) . 該類將產生相同的輸出。正如您所看到的,再也不用顯式地調用 Class.forName() .

          異常處理

          怎樣辨別一個 Java 程序的健壯與否呢 ? 在我看來,異常處理機制是重要的考慮因素之一 . 一個健壯的 Java 程序可以很好地處理異常 , 并給予程序在發生異常時恢復的能力 . 而一個不健壯的程序將導致輸出錯誤的結果甚至導致整個應用的崩潰 !

          JDBC 4.0 增加了一些簡單而有力的異常處理機制 , 其中值得一提的是鏈式異常,如果這個異常鏈存在的話,即可應用增強了的 for - each 循環來獲取異常鏈 ,. 下面的 Example2 類的局部結構展示了如何應用這種新的方法處理鏈式異常:

           

          public class Example2 {

            public static void main(String[] args) {

              String dbName = "example";

              String tableName = "student4";

              try {

                con = ds.getConnection();

                    stmt = con.createStatement();

                rs = stmt.executeQuery("select * from " + tableName);

              } catch (SQLException sx) {

                for(Throwable e : sx ) {

                  System.err.println("Error encountered: " + e);

                }

              }

              finally{

                //close connections

              }

            }

          }

           

          運行 Example2.java , 注意 student4 并不是數據庫中實際存在的表 . 將在下列調用中產生鏈式異常:

           

          rs = stmt.executeQuery("select * from " + tableName);

           

          在實際的應用中,需要捕捉到這些異常 , 檢測并進行相應的處理 . 在本例中,筆者僅將其在控制臺輸出 . 以下是輸出代碼:

           

          for(Throwable e : sx ) {

            System.err.println("Error encountered: " + e);

          }

           

          以下是類 Example2 輸出的結果 :

           

          Error encountered: java.sql.SQLSyntaxErrorException:

             Table/View 'STUDENT4' does not exist.

          Error encountered: java.sql.SQLException:

             Table/View 'STUDENT4' does not exist.

          Exception in thread "main" java.lang.NullPointerException

             at ex.Examlpe2.main(Examlpe2.java:51)

           

          通過應用 JDBC 4.0, 您現在不需太多代碼即可以獲取及遍歷異常鏈 . 在以往的版本中 , 您在遍歷異常鏈時,必須手工的調用 getNextException 方法才能得到相同的效果 .

          支持的數據類型

          本版 JDBC 增加了一些新的數據類型,對其他的一些數據類型,則提供了更好的支持 . 筆者為 XML 被正式支持感到欣喜 , 本版中產生了一個新的接口 : SQLXML . 在筆者看來這個接口值得單獨開一個章節為其討論:

          SQLXML XML 的支持

          SQLXML SQL XML 數據類型在 Java 中的表示, XML SQL 中用于表示表中 XML 數據的內建數據類型 . 在默認的情況下, JDBC 驅動將 SQLXML 指針指向 XML 數據而不是數據本身 . SQLXML 對象在其被創建的事務中是穩定的 .

          在下面的 Example3 類中 , 筆者將說明如何在當前連接中應用 SQLXML 并更新表數據 .

            public class Example3 {

              public static void main(String[] args) {

                ...

                con = ds.getConnection();

                SQLXML sx= con.createSQLXML();

                sx.setString("Math is Fun");

                String psx ="insert into "+tableName+

                  " ( id, textbook) values(?,?) ";

                PreparedStatement pstmt = con.prepareStatement(psx);

                pstmt.setString(1,"1000");

                pstmt.setSQLXML(2,sx);

                pstmt.executeUpdate();

                    ...

                }

              }

          這個例子說明了您所能應用的最簡單的情況 . 如果我們繼續深入研究,事情就會變得有趣得多了 . 但在我們深入討論之前 , 讓我來告訴您運行 Example3.java . 的結果。 非常不幸 , 我無法獲取到 SQLXML 對象,并得到了以下讓人失望的輸出:

          java.sql.SQLFeatureNotSupportedException: Feature not

             implemented: no details.

          at org.apache.derby.impl.jdbc.SQLExceptionFactory40.

             getSQLException(Unknown Source)

          ... ... ... ...

          at ex.Example3.main(Example3.java:62)

          看來 Apache Derby 并沒有提供從 Connection 中獲取 SQLXML 對象的方法 . 但至少您可以看到筆者正試圖在類 Example3 中實現的東西 : 我想插入一行新的數據: id 列值為 1000 textbook (S QLXML 類型 ) 插入 Math is Fun .

          筆者用如下代碼段結束關于 SQLXML 的討論,這段代碼從數據庫中讀取 XML 值并將其轉化為 Document 對象 .

          SQLXML sqlxml = rs.getSQLXML(column);

          InputStream binaryStream = sqlxml.getBinaryStream();

          DocumentBuilder parser =

            DocumentBuilderFactory.newInstance().newDocumentBuilder();

          Document doc = parser.parse(binaryStream);

          可以把一個列的值直接轉化為 XML 文檔不是一件令人興奮的事情嗎 ? 我覺得這個特性非常好 .

          ROWID 數據類型

          SQL ROWID 唯一標識了數據表中的一行,并是訪問該行的最快的方法, 本版增加了 RowId 接口以提供對 ROWID SQL 數據類型在 Java 類中的支持 .

          對大對象類型支持的增強

          JDBC 版本 2 提供了對大的 SQL 對象如: CLOB , BLOB , ARRAY 的支持 , 及用于添加相關接口的 Struct: Clob , Blob , Array , and Struct . 在本版的 JDBC 中增加了很多對這些對象訪問的新方法 . 筆者將在 API 變化一節中進行詳細論述 .

          支持 National Character Set NCS 轉化

          SQL:2003 提出了如下 SQL 數據類型的支持: NCHAR , NVARCHAR , LONGNVARCHAR , NCLOB . 其功用和 CHAR , VARCHAR , LONGVARCHAR , CLOB 類似 ,其區別僅是,這些類型的文本是用 NCS 編碼的。 如果需要大量的字符處理,您可能更傾向于 NCS 數據類型而非普通的數據類型。本版 JDBC 提供了增強對 NCS 支持的 API.

          • PreparedStatement , CallableStatement , ResultSet 接口中增加了一些 setter updater 方法以支持 NCS 轉化 . 比如方法 setNString , setNCharacterStream , setNClob 等等 .
          • SQLInput and SQLOutput 接口中增加了讀寫方法以支持 t NClob NString 對象 .

          API 變化

          JDBC 4.0 最大的變化來自于 API, 筆者在本小節對其做簡單介紹 .

          Array

          Array 接口增加了一個 free 方法來釋放 array 對象及其持有的資源 .

          Connection PooledConnection

          Connection 接口現在提供一系列創建大對象的方法如 createClob , createBlob 等等 . 此外還有 getter setter 對客戶端信息的重載方法 , 及驗證當前連接正確性的方法 .

          PooledConnection 接口當前提供 addStatementEventListener removeStatementEventListener 兩個方法來注冊和注銷 StatementEventListener 接口 , 這個接口是在本版 JDBC 中新引入的 . 這個接口的一個實例將獲取到 S tatement 池中 PreparedStatement s 的變化 . 比如,在注冊以后 , 當驅動調用 statementClosed 方法時,所有 StatementEventListener 將獲得 statement 已關閉的通知 .

          DatabaseMetaData

          不同的關系數據庫往往支持不同的特性 , 并通過不同的方法來實現這些特性 , 并可能會是用不同的數據類型 . 這將會導致移植性的問題,因為根據實現的不同,無法保證代碼在所有關系數據庫上都能正確執行 . 這樣的問題在一定程度上可以通過這個接口所獲得的信息來解決 . 比如,如果您在寫一個通過傳入 SQL 語句來建立表的代碼 . 您可能想知道在 CREATE TABLE 語句中有哪些數據類型是可用的,此時可以調用該接口中的 getTypeInfo 方法 .

          本版 JDBC 增加了一些獲取信息的方法 . Example4 , 我將通過一段代碼展示如何獲得滿足某種模式的數據庫結構的列表。 .

           

          con = ds.getConnection();

          DatabaseMetaData dmd = con.getMetaData();

          rs=dmd.getSchemas("TABLE_CAT", "SYS%");

          //iterate over the rs and print to console

           

          首先通過調用 dmd.getCatalogs 并遍歷結果集 , 得到了唯一的一個值: TABLE_CAT . 接著通過調用 rs=dmd.getSchemas("TABLE_CAT", "SYS%") 得到以 SYS 開頭的數據庫和表結構 . 以下是筆者得到的結果 :

           

          SYS

          SYSCAT

          SYSCS_DIAG

          SYSCS_UTIL

          SYSFUN

          SYSIBM

          SYSPROC

          SYSSTAT

           

          Scalar 函數支持

          一個 scalar 函數操作預定義的輸入數據集合并返回結果 . 比如: scalar 函數調用 ABS(number) 返回 number 的絕對值 . 這些 scalar 函數可以作為 SQL 字符串的一部分來使用 . 本版 JDBC 要求當所依賴的關系數據庫支持以下功能時: CHAR_LENGTH , CHARACTER_LENGTH , CURRENT_DATE , CURRENT_TIME , CURRENT_TIMESTAMP , EXTRACT , OCTET_LENGTH , POSITION ,驅動必須實現這些功能。

          Statement , PreparedStatement , CallableStatement

          Statement 接口當前提供 isClosed 方法來判斷 statement 是否已關閉 , setPoolable 用來設置是否可以被池化 , isPoolable 來檢測當前的池化狀態。

          PreparedStatement CallableStatement 接口現在提供了更多插入大對象的方法 , 通過使用 InputStream Reader .

          Wrapper

          這個版本的 API 增加了一個新的 Wrapper 接口, 來提供一種訪問資源的實例的方法 , 這可能是基于架構的考慮 . Wrapper 模式 , 被許多的 JDBC 驅動實現應用以提供 JDBC API 之外的依賴于具體數據源的應用 . 這個接口的主要目的是用來提供供應商相關的功能。您可以通過調用 unwrap 方法來獲取到數據庫連接的接口實現的實例 . 因為這是一個重量級的操作 , 在使用前,應該先調用 isWrapperFor 方法來檢測是否當前實例是某種實現的一個間接或直接的 Wapper

          能夠給出一個程序例子當然是最好的,但是 Apache Derby 參考手冊 l 指出 : "JDBC 4.0 引入了 wrapped JDBC 對象的概念 ... 對于 Derby 來說 , 這對 Derby 來說是沒有意義的,因為 Derby 并不做規范之外的擴展 ." 因此看來這種嘗試也就變得無甚必要了 !

          結論

          我們已經分為 4 類討論了 JDBC 4.0 所做的一些改進和新的特性,這些新特性增加了編程易用性,提高了生產率 . 盡管 API 規范已經推出幾個月了 , 到筆者截稿時,主流的數據庫廠商都沒有提供本版的 JDBC 驅動 . 當更多的供應商開始支持 JDBC 4.0 當然也包括您所中意的那個 您就可以享受 JDBC4.0 所提供的這些易用的功能了 .

          最后,我認為有一個各大數據庫廠商的支持的 JDBC 版本的列表是必要的 . Sun Developer Network (SDN) 上有一個 JDBC Data Access API http://developers.sun.com/product/jdbc/drivers 頁提供了一份更新不太及時的列表 .
           
          原作者信息:
          Sharad Acharya has more than eight years of experience in the software engineering field in multiple business domains including supply chain, insurance, banking, and mortgage.



           @2008 楊一. 版權所有. 保留所有權利

          posted on 2007-04-24 16:25 楊一 閱讀(3386) 評論(2)  編輯  收藏 所屬分類: Java EE

          評論

          # re: [譯]JDBC4.0具有哪些新特性? 2007-05-03 21:56 星泉

          呵呵 長見識了 五一回家剛看了些Java6的特性 回頭做兩個例子試試傳說中的4.0  回復  更多評論   

          # re: [譯]JDBC4.0具有哪些新特性? 2008-05-20 16:52 dfdf

          import java.sql.*;
            回復  更多評論   

          <2007年4月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導航

          公告

          本人在blogjava上發表的文章及隨筆除特別聲明外均為原創或翻譯,作品受知識產權法保護并被授權遵從 知識分享協議:署名-非商業性使用-相同方式共享 歡迎轉載,請在轉載時注明作者姓名(楊一)及出處(www.aygfsteel.com/yangyi)
          /////////////////////////////////////////
          我的訪問者

          常用鏈接

          留言簿(5)

          隨筆分類(55)

          隨筆檔案(55)

          相冊

          Java

          其他技術

          生活

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          自強不息


          用心 - 珍惜時間,勇于創造
          主站蜘蛛池模板: 文水县| 双柏县| 左云县| 象州县| 遵化市| 从江县| 吴川市| 莫力| 宜章县| 沁水县| 沅陵县| 察雅县| 科技| 淮安市| 洱源县| 玉龙| 久治县| 二连浩特市| 错那县| 榕江县| 巩义市| 襄樊市| 浮梁县| 竹溪县| 霍州市| 铜山县| 平凉市| 新龙县| 广饶县| 泽州县| 当阳市| 温州市| 红河县| 九台市| 城口县| 凤山市| 明溪县| 乡城县| 喀什市| 富裕县| 咸丰县|