快取記憶體行集(Cached Row Set)是 Java™ 1.5 提供的一項新功能,源自 JSR114 的努力。這一新功能使您可以擁有一個可串列化的中斷連接的物件。這意味著您可以連接到資料庫,以結果集的形式取得資料,釋放連接並在本地操縱這些資料,然後恢復連接以完成事務,這樣可以大大減少對連接和伺服器資源的使用。本文展示這一切是如何利用 DB2® Universal Database™ 來實作的,並包含範例代碼。
簡介
應該把資料庫連接看作是一種被應用程式廣泛使用的寶貴資源。尤其是在高流量的 Web 網站中,客戶機應該使用由應用程式伺服器(例如,IBM WebSphere® Application Server)管理的資料庫連接池中的資料庫連接,並在其必要的事務發生之後釋放資料庫連接,這一點很重要。
在許多情況下,事務會話會持續較長一段時間,佔用著資料庫連接,直到完成。過去,Java 程式師一直使用沒有快取記憶體解決方案的 JDBC API。快取記憶體解決方案允許用戶在本地快取記憶體結果集,釋放連接,操縱結果集資料,並在稍後的時間點與資料庫同步。在本文中,我將介紹 javax.sql.RowSet
介面的實作,該實作允許我們實作快取記憶體解決方案。
獲得 RowSet 實作
javax.sql.RowSet
介面是在 J2SE Version 1.4 中引入到 Java 語言的。隨著 Java 2 Standard Edition version 1.5 的發佈,我們將會看到該介面的增強和繫結到語言的介面實作。RowSet
介面是 JSR 114 的結果,JSR 114 勾勒了一個方案,也就是“將表格資料與資料源分隔開……”,從而增加“應用程式的可擴展性和編程模型的靈活性”。我使用 beta 版本的 Tiger (Java 1.5) 來進行開發。如果您使用的是以前版本的 Java,應該嘗試 RowSet 的參考實作,可以 從 Sun Microsystems 下載參考實作。對於我們的例子,我們將利用 CachedRowSet
實作。
您以前看到過 RowSet 實作
本文中突出展示的 CachedRowSetImpl
類別是 javax.sql.Rowset
介面的一個實作。javax.sql.Rowset
擴展了 java.sql.ResultSet
介面。因此,如果您熟悉 javax.sql.ResultSet
介面,我是這樣假設的,那麼您會認出 CachedRowSetImpl
提供的許多方法。java.sql.RowSet
介面提供您在標準 JDBC 2.0 ResultSet 中看到過的所有方法;附加價值是,我們不需要連續使用資料庫連接。就相當於我們可以走進商店,取走商品目錄之後進行挑選,然後再帶著填好的訂單回到商店。
使用 CachedRowSet
CachedRowSet
是一個 JavaBean。您可以通過使用現有的 ResultSet
物件,或者通過指定連接連接資訊和 SQL 查詢,來填滿 CachedRowSet
。我們採用後一種方法。但是,首先為我們的沙箱創建一個小的 DB2 資料庫。
|
我假設在您的機器上具有一個叫做 db2admin 的用戶,口令為 db2admin:
|
創建一個名為 cachetbl 的表:
|
然後用以下行填滿該表:
|
我提供的範例代碼建立一個到 DB2 的直接連接。如果您是通過由應用程式伺服器(比如 IBM WebSphere Application Server)管理的池獲得資料庫連接,那麼可以使用 execute
方法的另一種形式,該方法利用 java.sql.Connection
對象作為參數。通過閱讀我的相關主題的文章 Using Data Sources the Right Way,可以更多地瞭解使用資料源 —— 一種 J2EE 最佳實踐。
可串列化
javax.sql.RowSet
的實作可以被串列化。對於處理 Enterprise Java Beans 的程式師來說,這是一個比較好的訊息。標準 JDBC 2.0 ResultSets
是不可串列化的,這使得是否需要使用定制物件,以便 ResultSet
資料可以被發送回 EJB 設定中的客戶機以進行操縱或查詢,成了一個爭論。有了 RowSet
實作的出現,我們就可以串列化 ResultSets
,將它們發送到我們的客戶機,然後我們的客戶機可以讀取和更新 ResultSet
,並將它發送回伺服器。
可捲動
CachedRowSetImpl
實作是可捲動的,所以允許您在 RowSet
給出的記錄集中向前和向後捲動。這在 JDBC 2.0 ResultSet
中是允許的。但是以前,在捲動發生期間必須維護一個會話。現在,我們可以在離線資料中捲動了。
作一個資料完整性的樂天派
您可能會想,如果在客戶機 A 將更改與資料庫伺服器進行同步之前,客戶機 A 上快取的資料被另一個客戶機(客戶機 B)操縱,那將會發生什麼事情。CachedRowSet
的預設實作不對資料庫伺服器維護鎖。參考實作使用樂觀的同步。具體地說就是,如果客戶機 A 試圖操縱的資料在資料庫伺服器上沒有更改,那麼更新將會被資料庫接受。但是,如果在次期間目標資料被更改,就會拋出一個同步異常。注意,這種樂觀方法也是參考實作處理併發性的方式。其他實作可能採取不同的併發策略;規範並不強制要求使用某個特定的併發模型。
查看起作用的東西
我提供了一個 示例程式,該程式展示了 CachedRowSetImpl
提供的一些功能。這些代碼都可以在檔 DisconnectedExample.java
中找到。我將解釋該程式的一些部分,以便您可以理解我想要傳達的內容。注意,要運行示例應用程式,需要在運行時類別路徑中包含 DB2 Universal JDBC 驅動程式 (db2jcc.jar)。還需要包含 db2jcc_license_cu.jar 文件。關於設定環境的更多資訊,請參考我的文章:Hooking Up with DB2 Universal Database Version 8 using Java。
|
在上面的代碼中,我建立了一個 com.sun.rowset.CachedRowSetImpl
對象。注意我是如何為 CachedRowsetImpl
物件指定資料庫連接資訊的。我用 setCommand
方法來指定想要執行的查詢。當發出 execute
方法時,就會填滿 CachedRowSetImpl
對象。就是在該方法呼叫中,我們獲得然後再關閉資料庫連接。然後我可以在物件中迭代,並使用 getter 方法來抽取和報告其中包含的資料。
正如前面所提到的,CachedRowSetImpl
物件是可捲動的。下面的代碼範例展示了這項功能,我在該代碼中使用 last()
和 previous()
方法在資料間前後捲動。
|
方法 first()
和 next()
也可用於在資料間捲動。
為了展示從資料庫中斷連接的能力,範例程式設計為暫停,並讓您實際地執行生動的操作,即停止 DB2,以真正瞭解 CachedRowSet
功能的優勢。在繼續操作(由完成 BufferedReader
物件的一個簡單 readLine
而推動)之前,應用程式等待按下任意鍵。當範例程式提示您停止 DB2 時,可以在一個新的 DB2 命令行處理器視窗中使用下面的命令:
|
然後再使用
|
來強迫 DB2 的停止。
儘管資料庫已經停止,但是下面的代碼必須執行:
|
在上面的代碼中,我們更改了當前行目錄的 last name 欄位。注意,對 CachedRowSetImpl
物件使用了 updateRow()
方法,以記錄對該物件的更改。在這一時間點,資料庫還沒有被更新。正如您可以回想起的,資料庫 甚至沒有運行。應用程式將提示您啟動 DB2。為此,可以從 DB2 命令行處理器發出下面的命令:
|
在 DB2 啟動之後,按任意鍵繼續示例應用程式。
此時,下面的代碼將會運行,這將有效地在資料庫中同步更改。
|
通過對 cachetbl 執行一個選擇查詢,可以確認資料庫實際上已經更新,如 圖 1 所示:
為了結束我們對 CachedRowSet
的動手研究,範例應用程式還展示了如何插入和刪除行。要執行插入,必須將游標移動到一個叫做“插入行”的特殊位置。在這裏,我們使用更新方法來填滿新行。當我們使用 insertRow()
方法時,CachedRowSetImpl
物件就會被更新。當執行 acceptChanges()
方法時,更改就被持久地儲存到資料庫中。
以下代碼展示了這一點:
|
在插入完成之後程式將會暫停,以允許您在資料庫中查詢插入。
從物件刪除行相當直觀。只需要將游標定位到想要刪除的地方,然後使用 deleteRow
方法即可。跟前面一樣,需要一個後續的同步,以將更改持久儲存到資料庫中:
|
只是一種實作
讀者應該注意,javax.sql.RowSet
介面的 CachedRowSetImpl
實作只是一種實作(更確切地說是參考實作)。其他供應商也擁有 RowSet
的實作,這些實作與參考實作處理問題(比如資料完整性)的方式可能會不同(例如,第三方實作可能會對伺服器進行鎖維護)。
普遍含義
可更新的“中斷連接的” ResultSets
在普遍世界中具有各種含義,其中,網路連接可以是斷斷續續的。使用 CachedRowSet
可以允許客戶機在連接可用時將資料快取在本地,然後重新連接,以同步對資料執行的更改。
謹慎使用
中斷連接具有其優點。但是用戶必須理解,中斷連接的物件是儲存在記憶體中。因此,不應該使用具有大型結果集的方法。大型結果集的相應更新和捲動會是耗資源的操作。
結束語
與標準 JDBC 2.0 ResultSet
不一樣,利用 CachedRowSet
不再需要連續使用資料庫連接。因為資料庫連接池中的資料庫連接是寶貴的資源,所以連接資料庫、中斷連接,然後重新連接以便同步資料庫,這種能力無疑是非常受歡迎的。