利用 DB2 UDB 來使用 Java CachedRowSet 實現
斷開連接






將此頁作為電子郵件發送


未顯示需要 JavaScript 的文檔選項


樣例代碼
級別: 初級
Kulvir Singh Bhogal (kbhogal@us.ibm.com), IBM Software Services for WebSphere, IBM Corporation
2004 年 8 月 01 日
高速緩存行集(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 數據庫。
db2 => create database cachedex
我假設在您的機器上具有一個叫做 db2admin 的用戶,口令為 db2admin:
db2=> connect to cachedex user db2admin using db2admin
創建一個名為 cachetbl 的表:
db2=> create table cachetbl (id int primary key not null, firstname varchar(40) not null, lastname varchar(40) not null)
然后用以下行填充該表:
insert into cachetbl values (12345,’Kulvir’,’Bhogal’)
insert into cachetbl values (23456,’Meet’,’Feona’)
insert into cachetbl values (34567,’Bicky’,’Singh’)
我提供的示例代碼建立一個到 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。
Class.forName("com.ibm.db2.jcc.DB2Driver");
CachedRowSet crs = new CachedRowSetImpl();
crs.setUsername("db2admin"); crs.setPassword("db2admin"); crs.setUrl("jdbc:db2://localhost:50000/cachedex"); crs.setCommand("SELECT id,firstname,lastname from cachetbl");
crs.execute();
System.out.println("---------------------------");
// display size of cached row set
System.out.println("Size: " + crs.size() + " records");
// display records in cachedrowset
while (crs.next())
{
System.out.println(crs.getRow() + " - " + crs.getString("firstname") + " " + crs.getString("lastname"));
}
System.out.println("---------------------------");
在上面的代碼中,我創建了一個 com.sun.rowset.CachedRowSetImpl 對象。注意我是如何為 CachedRowsetImpl 對象指定數據庫連接信息的。我用 setCommand 方法來指定想要執行的查詢。當發出 execute 方法時,就會填充 CachedRowSetImpl 對象。就是在該方法調用中,我們獲得然后再關閉數據庫連接。然后我可以在對象中迭代,并使用 getter 方法來抽取和報告其中包含的數據。
正如前面所提到的, CachedRowSetImpl 對象是可滾動的。下面的代碼例示了這項功能,我在該代碼中使用 last() 和 previous() 方法在數據間前后滾動。
System.out.println("Showcase scrollability");
// move backwards through rowset
// scroll to last row
crs.last();
// iterate to next row
while (crs.previous())
{
// report current row contents
System.out.println(crs.getRow() + " - " + crs.getString("lastname"));
}
方法 first() 和 next() 也可用于在數據間滾動。
為了演示從數據庫斷開連接的能力,示例程序設計為暫停,并讓您實際地執行生動的操作,即停止 DB2,以真正了解 CachedRowSet 功能的優勢。在繼續操作(由完成 BufferedReader 對象的一個簡單 readLine 而推動)之前,應用程序等待按下任意鍵。當示例程序提示您停止 DB2 時,可以在一個新的 DB2 命令行處理器窗口中使用下面的命令:
db2 force applications all
然后再使用
db2stop
來強迫 DB2 的停止。
盡管數據庫已經停止,但是下面的代碼必須執行:
System.out.println("Demonstration of how to update cached row set"); crs.updateString("lastname","Kaur");
// commit changes to cached portion of rowset
crs.updateRow();
System.out.println(crs.getRow() + " - " + crs.getString("lastname"));
在上面的代碼中,我們更改了當前行條目的 last name 字段。注意,對 CachedRowSetImpl 對象使用了 updateRow() 方法,以記錄對該對象的更改。在這一時間點,數據庫還沒有被更新。正如您可以回想起的,數據庫 甚至沒有運行。應用程序將提示您啟動 DB2。為此,可以從 DB2 命令行處理器發出下面的命令:
db2start
在 DB2 啟動之后,按任意鍵繼續示例應用程序。
此時,下面的代碼將會運行,這將有效地在數據庫中同步更改。
crs.acceptChanges();
通過對 cachetbl 執行一個選擇查詢,可以確認數據庫實際上已經更新,如 圖 1所示:
圖 1. 確認更新更改已經與數據庫同步

為了結束我們對 CachedRowSet 的動手研究,示例應用程序還演示了如何插入和刪除行。要執行插入,必須將光標移動到一個叫做“插入行”的特殊位置。在這里,我們使用更新方法來填充新行。當我們使用 insertRow() 方法時, CachedRowSetImpl 對象就會被更新。當執行 acceptChanges() 方法時,更改就被持久地存儲到數據庫中。
以下代碼演示了這一點:
// move the cursor to a blank row crs.moveToInsertRow();
// populate the new row
crs.updateInt(1,01234);
crs.updateString(2,"Judith");
crs.updateString(3,"Smith");
// insert the new row
crs.insertRow();
// move cursor back to previous position
crs.moveToCurrentRow();
// synchronize changes to database
crs.acceptChanges();
在插入完成之后程序將會暫停,以允許您在數據庫中查詢插入。
從對象刪除行相當直觀。只需要將光標定位到想要刪除的地方,然后使用 deleteRow 方法即可。跟前面一樣,需要一個后續的同步,以將更改持久存儲到數據庫中:
// delete row (where the cursor is currently positioned)
crs.deleteRow();
// synchronize changes to database
crs.acceptChanges();




回頁首
只是一種實現
讀者應該注意, javax.sql.RowSet 接口的 CachedRowSetImpl 實現只是一種實現(更確切地說是參考實現)。其他供應商也擁有 RowSet 的實現,這些實現與參考實現處理問題(比如數據完整性)的方式可能會不同(例如,第三方實現可能會對服務器進行鎖維護)。




回頁首
普遍含義
可更新的“斷開連接的” ResultSets 在普遍世界中具有各種含義,其中,網絡連接可以是斷斷續續的。使用 CachedRowSet 可以允許客戶機在連接可用時將數據緩存在本地,然后重新連接,以同步對數據執行的更改。




回頁首
謹慎使用
斷開連接具有其優點。但是用戶必須理解,斷開連接的對象是保存在內存中。因此,不應該使用具有大型結果集的方法。大型結果集的相應更新和滾動會是耗資源的操作。




回頁首
結束語
與標準 JDBC 2.0 ResultSet 不一樣,利用 CachedRowSet 不再需要連續使用數據庫連接。因為數據庫連接池中的數據庫連接是寶貴的資源,所以連接數據庫、斷開連接,然后重新連接以便同步數據庫,這種能力無疑是非常受歡迎的。




回頁首
致謝
作者感謝 IBM Life Sciences Development 的 Richard Dettinger 對本文的審稿。




回頁首
下載
名字 大小 下載方法
DisconnectedExample.java
4.03 KB
HTTP


關于下載方法的信息


Get Adobe® Reader®
參考資料
關于作者



Kulvir Singh Bhogal 是一名 IBM 顧問,他為全國性的客戶網站設計和實現以 Java 為中心的解決方案。 .
源文檔 <http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0406bhogal/index.html>