利用 DB2 UDB 來使用 Java CachedRowSet 實(shí)現(xiàn)
斷開連接






將此頁作為電子郵件發(fā)送


未顯示需要 JavaScript 的文檔選項(xiàng)


樣例代碼
級(jí)別: 初級(jí)
Kulvir Singh Bhogal (kbhogal@us.ibm.com), IBM Software Services for WebSphere, IBM Corporation
2004 年 8 月 01 日
高速緩存行集(Cached Row Set)是 Java™ 1.5 提供的一項(xiàng)新功能,源自 JSR114 的努力。這一新功能使您可以擁有一個(gè)可串行化的斷開連接的對(duì)象。這意味著您可以連接到數(shù)據(jù)庫,以結(jié)果集的形式取得數(shù)據(jù),釋放連接并在本地操縱這些數(shù)據(jù),然后恢復(fù)連接以完成事務(wù),這樣可以大大減少對(duì)連接和服務(wù)器資源的使用。本文展示這一切是如何利用 DB2® Universal Database™ 來實(shí)現(xiàn)的,并包含示例代碼。
簡介
應(yīng)該把數(shù)據(jù)庫連接看作是一種被應(yīng)用程序廣泛使用的寶貴資源。尤其是在高流量的 Web 站點(diǎn)中,客戶機(jī)應(yīng)該使用由應(yīng)用程序服務(wù)器(例如,IBM WebSphere® Application Server)管理的數(shù)據(jù)庫連接池中的數(shù)據(jù)庫連接,并在其必要的事務(wù)發(fā)生之后釋放數(shù)據(jù)庫連接,這一點(diǎn)很重要。
在許多情況下,事務(wù)會(huì)話會(huì)持續(xù)較長一段時(shí)間,占用著數(shù)據(jù)庫連接,直到完成。過去,Java 程序員一直使用沒有高速緩存解決方案的 JDBC API。高速緩存解決方案允許用戶在本地高速緩存結(jié)果集,釋放連接,操縱結(jié)果集數(shù)據(jù),并在稍后的時(shí)間點(diǎn)與數(shù)據(jù)庫同步。在本文中,我將介紹 javax.sql.RowSet 接口的實(shí)現(xiàn),該實(shí)現(xiàn)允許我們實(shí)現(xiàn)高速緩存解決方案。




回頁首
獲得 RowSet 實(shí)現(xiàn)
javax.sql.RowSet 接口是在 J2SE Version 1.4 中引入到 Java 語言的。隨著 Java 2 Standard Edition version 1.5 的發(fā)布,我們將會(huì)看到該接口的增強(qiáng)和綁定到語言的接口實(shí)現(xiàn)。 RowSet 接口是 JSR 114的結(jié)果,JSR 114 勾勒了一個(gè)方案,也就是“將表格數(shù)據(jù)與數(shù)據(jù)源分隔開……”,從而增加“應(yīng)用程序的可擴(kuò)展性和編程模型的靈活性”。我使用 beta 版本的 Tiger (Java 1.5) 來進(jìn)行開發(fā)。如果您使用的是以前版本的 Java,應(yīng)該嘗試 RowSet 的參考實(shí)現(xiàn),可以 從 Sun Microsystems 下載參考實(shí)現(xiàn)。對(duì)于我們的例子,我們將利用 CachedRowSet 實(shí)現(xiàn)。




回頁首
您以前看到過 RowSet 實(shí)現(xiàn)
本文中突出展示的 CachedRowSetImpl 類是 javax.sql.Rowset 接口的一個(gè)實(shí)現(xiàn)。 javax.sql.Rowset 擴(kuò)展了 java.sql.ResultSet 接口。因此,如果您熟悉 javax.sql.ResultSet 接口,我是這樣假設(shè)的,那么您會(huì)認(rèn)出 CachedRowSetImpl 提供的許多方法。 java.sql.RowSet 接口提供您在標(biāo)準(zhǔn) JDBC 2.0 ResultSet 中看到過的所有方法;附加價(jià)值是,我們不需要連續(xù)使用數(shù)據(jù)庫連接。就相當(dāng)于我們可以走進(jìn)商店,取走商品目錄之后進(jìn)行挑選,然后再帶著填好的訂單回到商店。




回頁首
使用 CachedRowSet
CachedRowSet 是一個(gè) JavaBean。您可以通過使用現(xiàn)有的 ResultSet 對(duì)象,或者通過指定連接連接信息和 SQL 查詢,來填充 CachedRowSet 。我們采用后一種方法。但是,首先為我們的沙箱創(chuàng)建一個(gè)小的 DB2 數(shù)據(jù)庫。
db2 => create database cachedex
我假設(shè)在您的機(jī)器上具有一個(gè)叫做 db2admin 的用戶,口令為 db2admin:
db2=> connect to cachedex user db2admin using db2admin
創(chuàng)建一個(gè)名為 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’)
我提供的示例代碼建立一個(gè)到 DB2 的直接連接。如果您是通過由應(yīng)用程序服務(wù)器(比如 IBM WebSphere Application Server)管理的池獲得數(shù)據(jù)庫連接,那么可以使用 execute 方法的另一種形式,該方法利用 java.sql.Connection 對(duì)象作為參數(shù)。通過閱讀我的相關(guān)主題的文章 Using Data Sources the Right Way,可以更多地了解使用數(shù)據(jù)源 —— 一種 J2EE 最佳實(shí)踐。




回頁首
可串行化
javax.sql.RowSet 的實(shí)現(xiàn)可以被串行化。對(duì)于處理 Enterprise Java Beans 的程序員來說,這是一個(gè)比較好的消息。標(biāo)準(zhǔn) JDBC 2.0 ResultSets 是不可串行化的,這使得是否需要使用定制對(duì)象,以便 ResultSet 數(shù)據(jù)可以被發(fā)送回 EJB 設(shè)置中的客戶機(jī)以進(jìn)行操縱或查詢,成了一個(gè)爭論。有了 RowSet 實(shí)現(xiàn)的出現(xiàn),我們就可以串行化 ResultSets ,將它們發(fā)送到我們的客戶機(jī),然后我們的客戶機(jī)可以讀取和更新 ResultSet ,并將它發(fā)送回服務(wù)器。




回頁首
可滾動(dòng)
CachedRowSetImpl 實(shí)現(xiàn)是可滾動(dòng)的,所以允許您在 RowSet 給出的記錄集中向前和向后滾動(dòng)。這在 JDBC 2.0 ResultSet 中是允許的。但是以前,在滾動(dòng)發(fā)生期間必須維護(hù)一個(gè)會(huì)話。現(xiàn)在,我們可以在離線數(shù)據(jù)中滾動(dòng)了。




回頁首
作一個(gè)數(shù)據(jù)完整性的樂天派
您可能會(huì)想,如果在客戶機(jī) A 將更改與數(shù)據(jù)庫服務(wù)器進(jìn)行同步之前,客戶機(jī) A 上緩存的數(shù)據(jù)被另一個(gè)客戶機(jī)(客戶機(jī) B)操縱,那將會(huì)發(fā)生什么事情。 CachedRowSet 的默認(rèn)實(shí)現(xiàn)不對(duì)數(shù)據(jù)庫服務(wù)器維護(hù)鎖。參考實(shí)現(xiàn)使用樂觀的同步。具體地說就是,如果客戶機(jī) A 試圖操縱的數(shù)據(jù)在數(shù)據(jù)庫服務(wù)器上沒有更改,那么更新將會(huì)被數(shù)據(jù)庫接受。但是,如果在次期間目標(biāo)數(shù)據(jù)被更改,就會(huì)拋出一個(gè)同步異常。注意,這種樂觀方法也是參考實(shí)現(xiàn)處理并發(fā)性的方式。其他實(shí)現(xiàn)可能采取不同的并發(fā)策略;規(guī)范并不強(qiáng)制要求使用某個(gè)特定的并發(fā)模型。




回頁首
查看起作用的東西
我提供了一個(gè) 示例程序,該程序演示了 CachedRowSetImpl 提供的一些功能。這些代碼都可以在文件 DisconnectedExample.java 中找到。我將解釋該程序的一些部分,以便您可以理解我想要傳達(dá)的內(nèi)容。注意,要運(yùn)行示例應(yīng)用程序,需要在運(yùn)行時(shí)類路徑中包含 DB2 Universal JDBC 驅(qū)動(dòng)程序 (db2jcc.jar)。還需要包含 db2jcc_license_cu.jar 文件。關(guān)于設(shè)置環(huán)境的更多信息,請(qǐng)參考我的文章: 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("---------------------------");
在上面的代碼中,我創(chuàng)建了一個(gè) com.sun.rowset.CachedRowSetImpl 對(duì)象。注意我是如何為 CachedRowsetImpl 對(duì)象指定數(shù)據(jù)庫連接信息的。我用 setCommand 方法來指定想要執(zhí)行的查詢。當(dāng)發(fā)出 execute 方法時(shí),就會(huì)填充 CachedRowSetImpl 對(duì)象。就是在該方法調(diào)用中,我們獲得然后再關(guān)閉數(shù)據(jù)庫連接。然后我可以在對(duì)象中迭代,并使用 getter 方法來抽取和報(bào)告其中包含的數(shù)據(jù)。
正如前面所提到的, CachedRowSetImpl 對(duì)象是可滾動(dòng)的。下面的代碼例示了這項(xiàng)功能,我在該代碼中使用 last() 和 previous() 方法在數(shù)據(jù)間前后滾動(dòng)。
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() 也可用于在數(shù)據(jù)間滾動(dòng)。
為了演示從數(shù)據(jù)庫斷開連接的能力,示例程序設(shè)計(jì)為暫停,并讓您實(shí)際地執(zhí)行生動(dòng)的操作,即停止 DB2,以真正了解 CachedRowSet 功能的優(yōu)勢(shì)。在繼續(xù)操作(由完成 BufferedReader 對(duì)象的一個(gè)簡單 readLine 而推動(dòng))之前,應(yīng)用程序等待按下任意鍵。當(dāng)示例程序提示您停止 DB2 時(shí),可以在一個(gè)新的 DB2 命令行處理器窗口中使用下面的命令:
db2 force applications all
然后再使用
db2stop
來強(qiáng)迫 DB2 的停止。
盡管數(shù)據(jù)庫已經(jīng)停止,但是下面的代碼必須執(zhí)行:
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"));
在上面的代碼中,我們更改了當(dāng)前行條目的 last name 字段。注意,對(duì) CachedRowSetImpl 對(duì)象使用了 updateRow() 方法,以記錄對(duì)該對(duì)象的更改。在這一時(shí)間點(diǎn),數(shù)據(jù)庫還沒有被更新。正如您可以回想起的,數(shù)據(jù)庫 甚至沒有運(yùn)行。應(yīng)用程序?qū)⑻崾灸鷨?dòng) DB2。為此,可以從 DB2 命令行處理器發(fā)出下面的命令:
db2start
在 DB2 啟動(dòng)之后,按任意鍵繼續(xù)示例應(yīng)用程序。
此時(shí),下面的代碼將會(huì)運(yùn)行,這將有效地在數(shù)據(jù)庫中同步更改。
crs.acceptChanges();
通過對(duì) cachetbl 執(zhí)行一個(gè)選擇查詢,可以確認(rèn)數(shù)據(jù)庫實(shí)際上已經(jīng)更新,如 圖 1所示:
圖 1. 確認(rèn)更新更改已經(jīng)與數(shù)據(jù)庫同步

為了結(jié)束我們對(duì) CachedRowSet 的動(dòng)手研究,示例應(yīng)用程序還演示了如何插入和刪除行。要執(zhí)行插入,必須將光標(biāo)移動(dòng)到一個(gè)叫做“插入行”的特殊位置。在這里,我們使用更新方法來填充新行。當(dāng)我們使用 insertRow() 方法時(shí), CachedRowSetImpl 對(duì)象就會(huì)被更新。當(dāng)執(zhí)行 acceptChanges() 方法時(shí),更改就被持久地存儲(chǔ)到數(shù)據(jù)庫中。
以下代碼演示了這一點(diǎn):
// 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();
在插入完成之后程序?qū)?huì)暫停,以允許您在數(shù)據(jù)庫中查詢插入。
從對(duì)象刪除行相當(dāng)直觀。只需要將光標(biāo)定位到想要?jiǎng)h除的地方,然后使用 deleteRow 方法即可。跟前面一樣,需要一個(gè)后續(xù)的同步,以將更改持久存儲(chǔ)到數(shù)據(jù)庫中:
// delete row (where the cursor is currently positioned)
crs.deleteRow();
// synchronize changes to database
crs.acceptChanges();




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




回頁首
普遍含義
可更新的“斷開連接的” ResultSets 在普遍世界中具有各種含義,其中,網(wǎng)絡(luò)連接可以是斷斷續(xù)續(xù)的。使用 CachedRowSet 可以允許客戶機(jī)在連接可用時(shí)將數(shù)據(jù)緩存在本地,然后重新連接,以同步對(duì)數(shù)據(jù)執(zhí)行的更改。




回頁首
謹(jǐn)慎使用
斷開連接具有其優(yōu)點(diǎn)。但是用戶必須理解,斷開連接的對(duì)象是保存在內(nèi)存中。因此,不應(yīng)該使用具有大型結(jié)果集的方法。大型結(jié)果集的相應(yīng)更新和滾動(dòng)會(huì)是耗資源的操作。




回頁首
結(jié)束語
與標(biāo)準(zhǔn) JDBC 2.0 ResultSet 不一樣,利用 CachedRowSet 不再需要連續(xù)使用數(shù)據(jù)庫連接。因?yàn)閿?shù)據(jù)庫連接池中的數(shù)據(jù)庫連接是寶貴的資源,所以連接數(shù)據(jù)庫、斷開連接,然后重新連接以便同步數(shù)據(jù)庫,這種能力無疑是非常受歡迎的。




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




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


關(guān)于下載方法的信息


Get Adobe® Reader®
參考資料
關(guān)于作者



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