教你使用Java中的RowSet
ResultSet是使用Jdbc編程的人入門(mén)和常用的操作數(shù)據(jù)庫(kù)的類(lèi),自 JDK 1.4 開(kāi)始,易于使用RowSet接口被引入。RowSet 接口擴(kuò)展了標(biāo)準(zhǔn) java.sql.ResultSet 接口。RowSetMetaData 接口擴(kuò)展了 java.sql.ResultSetMetaData 接口。因此,熟悉 JDBC API 的開(kāi)發(fā)人員必須學(xué)習(xí)少數(shù)幾個(gè)新 API 才能使用 rowset。此外,與 JDBC ResultSet 對(duì)象配套使用的第三方軟件工具也可以方便地用于 rowset。但是在JDK 1.4中,只有一個(gè)RowSet接口,使得RowSet的使用范圍打了折扣。不過(guò) JDK 5.0 定義了5 個(gè)標(biāo)準(zhǔn)的 JDBC RowSet 接口,并且給出了相應(yīng)的參考實(shí)現(xiàn),因此可以很方便的使用RowSet接口所提供的功能。
RowSet 對(duì)象可以建立一個(gè)與數(shù)據(jù)源的連接并在其整個(gè)生命周期中維持該連接,在此情況下,該對(duì)象被稱(chēng)為連接的 rowset。rowset 還可以建立一個(gè)與數(shù)據(jù)源的連接,從其獲取數(shù)據(jù),然后關(guān)閉它。這種 rowset 被稱(chēng)為非連接 rowset。非連接 rowset 可以在斷開(kāi)時(shí)更改其數(shù)據(jù),然后將這些更改發(fā)送回原始數(shù)據(jù)源,不過(guò)它必須重新建立連接才能完成此操作。 相比較 java.sql.ResultSet 而言,RowSet 的離線操作能夠有效的利用計(jì)算機(jī)越來(lái)越充足的內(nèi)存,減輕數(shù)據(jù)庫(kù)服務(wù)器的負(fù)擔(dān),由于數(shù)據(jù)操作都是在內(nèi)存中進(jìn)行然后批量提交到數(shù)據(jù)源,靈活性和性能都有了很大的提高。RowSet 默認(rèn)是一個(gè)可滾動(dòng),可更新,可序列化的結(jié)果集,而且它作為 JavaBeans,可以方便地在網(wǎng)絡(luò)間傳輸,用于兩端的數(shù)據(jù)同步。
1、與ResultSet比較
(1)RowSet擴(kuò)展了ResultSet接口,因此可以像使用ResultSet一樣使用RowSet。
(2)RowSet擴(kuò)展了ResultSet接口,因此功能比ResultSet更多、更豐富。
(3)默認(rèn)情況下,所有 RowSet 對(duì)象都是可滾動(dòng)的和可更新的。而ResultSet是只能向前滾動(dòng)和只讀的。
(4)RowSet可以是非鏈接的,而ResultSet是連接的。因此利用CacheRowSet接口可以離線操作數(shù)據(jù)。
(5)RowSet接口添加了對(duì) JavaBeans 組件模型的 JDBC API 支持。rowset 可用作可視化 Bean 開(kāi)發(fā)環(huán)境中的 JavaBeans 組件。
(6)RowSet采用了新的連接數(shù)據(jù)庫(kù)的方法。
(7)CacheRowSet是可以序列化的。
(8)RowSet和ResultSet都代表一行行的數(shù)據(jù)、屬性以及相關(guān)操作方法。
(9)自己認(rèn)為,應(yīng)該傾向于把RowSet看成是與數(shù)據(jù)庫(kù)無(wú)關(guān)的東西,它只是一個(gè)代表一行行數(shù)據(jù)的對(duì)象,而ResultSet則是一個(gè)與數(shù)據(jù)庫(kù)緊密聯(lián)系的東西。
2、JDK 5.0 的5個(gè)標(biāo)準(zhǔn)RowSet接口
在JDK 5.0中,5個(gè)標(biāo)準(zhǔn)RowSet接口包括 CachedRowSet,WebRowSet,F(xiàn)ilteredRowSet,JoinRowSet 和 JdbcRowSet。相應(yīng)的參考實(shí)現(xiàn)是Sun公司給出的,位于com.sun.rowset包下,分別為為CachedRowSetImpl,WebRowSetImpl,F(xiàn)ilteredRowSetImpl,JoinRowSetImpl 和 JdbcRowSetImpl。這5個(gè)標(biāo)準(zhǔn)接口中JdbcRowSet是鏈接的rowset,而其他4個(gè)是非鏈接的rowset。
(1)CachedRowSet:最常用的一種 RowSet。其他三種 RowSet(WebRowSet,F(xiàn)ilteredRowSet,JoinRowSet)都是直接或間接繼承于它并進(jìn)行了擴(kuò)展。它提供了對(duì)數(shù)據(jù)庫(kù)的離線操作,可以將數(shù)據(jù)讀取到內(nèi)存中進(jìn)行增刪改查,再同步到數(shù)據(jù)源。CachedRowSet是可滾動(dòng)的、可更新的、可序列化,可作為 JavaBeans 在網(wǎng)絡(luò)間傳輸。支持事件監(jiān)聽(tīng),分頁(yè)等特性。 CachedRowSet 對(duì)象通常包含取自結(jié)果集的多個(gè)行,但是也可包含任何取自表格式文件(如電子表格)的行。
(2)WebRowSet:繼承自 CachedRowSet,并可以將 WebRowSet 寫(xiě)到 XML 文件中,也可以用符合規(guī)范的 XML 文件來(lái)填充 WebRowSet。
(3)FilteredRowSet:通過(guò)設(shè)置 Predicate(在 javax.sql.rowset 包中),提供數(shù)據(jù)過(guò)濾的功能??梢愿鶕?jù)不同的條件對(duì) RowSet 中的數(shù)據(jù)進(jìn)行篩選和過(guò)濾。
(4)JoinRowSet:提供類(lèi)似 SQL JOIN 的功能,將不同的 RowSet 中的數(shù)據(jù)組合起來(lái)。目前在 Java 6 中只支持內(nèi)聯(lián)(Inner Join)。
(5)JdbcRowSet:對(duì) ResultSet 的一個(gè)封裝,使其能夠作為 JavaBeans 被使用,是***一個(gè)保持?jǐn)?shù)據(jù)庫(kù)連接的 RowSet。JdbcRowSet 對(duì)象是連接的 RowSet 對(duì)象,也就是說(shuō),它必須使用啟用 JDBC 技術(shù)的驅(qū)動(dòng)程序(“JDBC 驅(qū)動(dòng)程序”)來(lái)持續(xù)維持它與數(shù)據(jù)源的連接。
3、填充RowSet
前面說(shuō)過(guò),應(yīng)該傾向于把RowSet看成是與數(shù)據(jù)庫(kù)無(wú)關(guān)而只代表一行行數(shù)據(jù)的對(duì)象,因此就涉及到數(shù)據(jù)從哪里來(lái)的問(wèn)題。
(1)從數(shù)據(jù)庫(kù)直接獲取數(shù)據(jù)
由于大部分情況下,與數(shù)據(jù)打交道也就是與數(shù)據(jù)庫(kù)打交道,因此RowSet接口提供了通過(guò)JDBC直接從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)的方法,以參考實(shí)現(xiàn)JdbcRowSetImpl為例,就是這樣:
RowSet rs = new JdbcRowSetImpl(); //也可以是CachedRowSetImpl,WebRowSetImpl,F(xiàn)ilteredRowSetImpl,JoinRowSetImpl。
rs.setUrl("jdbc:mysql:///test");
rs.setUsername("root");
rs.setPassword("");
rs.setCommand("SELECT * FROM EMPLOYEES");
rs.execute();
設(shè)置好相關(guān)屬性,運(yùn)行execute()方法后,EMPLOYEES表中的數(shù)據(jù)就被填充到rs對(duì)象中了。
除了通過(guò)設(shè)置JDBC連接URL、用戶名和密碼外,RowSet也可以使用數(shù)據(jù)源名稱(chēng)屬性的值來(lái)查找已經(jīng)在命名服務(wù)中注冊(cè)的 DataSource 對(duì)象。完成檢索后,可以使用 DataSource 對(duì)象創(chuàng)建到它所表示的數(shù)據(jù)源的連接,設(shè)置數(shù)據(jù)源名稱(chēng)可以使用setDataSourceName()方法。
(2)用ResultSet填充
在有現(xiàn)成ResultSet的情況下,如果想將其作為RowSet使用;或者當(dāng) DBMS 不提供對(duì)滾動(dòng)和更新的完全支持時(shí),如果想使不可滾動(dòng)和只讀的 ResultSet 對(duì)象變得可滾動(dòng)和可更新,可以創(chuàng)建一個(gè)使用該 ResultSet 對(duì)象的數(shù)據(jù)所填充的 CachedRowSet 對(duì)象。
ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES");
CachedRowSet crs = new CachedRowSetImpl(); //也可以是WebRowSetImpl,F(xiàn)ilteredRowSetImpl,JoinRowSetImpl,因?yàn)樗麄兙^承自CachedRowSetImpl
crs.populate(rs);
運(yùn)行populate()方法后,ResultSet對(duì)象rs中的數(shù)據(jù)就被填充到crs對(duì)象中了。
(3)用XML填充
如果您打算將XML作為數(shù)據(jù)交換格式在客戶端和你的服務(wù)器之間傳輸數(shù)據(jù)并且向?qū)崿F(xiàn)數(shù)據(jù)離線編輯、或者向使用XML格式的數(shù)據(jù)的話,可以使用WebRowSet接口來(lái)用XML填充數(shù)據(jù)。
WebRowSet wrs = new WebRowSetImpl();
wrs.readXml(new FileReader(new File("D:\\employees.xml")));
運(yùn)行readXml()方法后,employees.xml文件的數(shù)據(jù)就被填充到wrs對(duì)象中了。employees.xml 文件的格式參見(jiàn)附錄。
(4)用其他方法填充
如果形用其他方式填充,比如csv、excel、text、http等格式或方法填充數(shù)據(jù),那么就需要自己編寫(xiě)代碼實(shí)現(xiàn)RowSet。
4、操作RowSet中的數(shù)據(jù)及元數(shù)據(jù)
除了ResultSet提供的操作數(shù)據(jù)和元數(shù)據(jù)方法外,RowSet接口沒(méi)有提供太多額外的方法。
1)更新數(shù)據(jù)
rs.absolute(5);
rs.updateInt(1, 10);
rs.updateInt(2, 1000);
rs.updateString(3, "John");
rs.updateRow();
(2)插入數(shù)據(jù)
rs.moveToInsertRow();
rs.updateInt(1, 10);
rs.updateInt(2, 1000);
rs.updateString(3, "John");
rs.insertRow();
(3)刪除數(shù)據(jù)
rs.absolute(5);
rs.deleteRow();
(4)設(shè)置屬性
rs.setCommand("select id, salary, name from employees where id = ?");
rs.setInt(1, 1);
rs.execute();
(5)元數(shù)據(jù)
RowSetMetaData rsmd = (RowSetMetaData)rs.getMetaData();
int count = rsmd.getColumnCount();
int type = rsmd.getColumnType(2);
5、事務(wù)與更新底層數(shù)據(jù)源
RowSet本身只代表具體數(shù)據(jù),事務(wù)以及底層數(shù)據(jù)源的更新是與底層數(shù)據(jù)源密切相關(guān)的概念。對(duì)于JDBC數(shù)據(jù)源,相應(yīng)的標(biāo)準(zhǔn)接口JdbcRowSet通過(guò)與數(shù)據(jù)庫(kù)相關(guān)的方法來(lái)來(lái)實(shí)現(xiàn),如commit(),rollback()等。對(duì)于標(biāo)準(zhǔn)接口的中非連接rowset,如CachedRowSet,則在對(duì)RowSet中的數(shù)據(jù)改動(dòng)后,通過(guò)運(yùn)行acceptChanges()方法,在內(nèi)部調(diào)用 RowSet 對(duì)象的 writer 將這些更改寫(xiě)入數(shù)據(jù)源,從而將 CachedRowSet 對(duì)象中的更改傳播回底層數(shù)據(jù)源。
6、可序列化非連接RowSet
使用 CachedRowSet 對(duì)象的主要原因之一是要在應(yīng)用程序的不同組件之間傳遞數(shù)據(jù)。因?yàn)?CachedRowSet 對(duì)象是可序列化的,所以可使用它(舉例來(lái)說(shuō))將運(yùn)行于服務(wù)器環(huán)境的企業(yè) JavaBeans 組件執(zhí)行查詢的結(jié)果通過(guò)網(wǎng)絡(luò)發(fā)送到運(yùn)行于 web 瀏覽器的客戶端。
由于 CachedRowSet 對(duì)象是非連接的,所以和具有相同數(shù)據(jù)的 ResultSet 對(duì)象相比更為簡(jiǎn)潔。因此,它特別適于向瘦客戶端(如 PDA)發(fā)送數(shù)據(jù),這種瘦客戶端由于資源限制或安全考慮而不適于使用 JDBC 驅(qū)動(dòng)程序。所以 CachedRowSet 對(duì)象可提供一種“獲取各行”的方式而無(wú)需實(shí)現(xiàn)全部 JDBC API。
ebRowSet繼承自CachedRowSet,除了擁有CachedRowSet的優(yōu)點(diǎn)外,還可以將WebRowSet輸出成XML,也可以將XML轉(zhuǎn)換成WebRowSet,更加適合在Web環(huán)境中使用。標(biāo)準(zhǔn)的 WebRowSet XML 模式定義位于 URI http://java.sun.com/xml/ns/jdbc/webrowset.xsd。將WebRowSet保存為XML的代碼事例如下:
wrs.setCommand("select id, salary, name from employees");
wrs.execute();
wrs.writeXml(new FileWriter(new File("D:\\employees.xml")));
【編輯推薦】