RowSet離線結果集物件的使用詳解

一隻小螞蟻吆發表於2020-04-06

ResultSet是使用Jdbc程式設計的人入門和常用的運算元據庫的類,自 JDK 1.4 開始,易於使用RowSet介面被引入。RowSet 介面擴充套件了標準 java.sql.ResultSet 介面。RowSetMetaData 介面擴充套件了 java.sql.ResultSetMetaData 介面。因此,熟悉 JDBC API 的開發人員必須學習少數幾個新 API 才能使用 rowset。此外,與 JDBC ResultSet 物件配套使用的第三方軟體工具也可以方便地用於 rowset。但是在JDK 1.4中,只有一個RowSet介面,使得RowSet的使用範圍打了折扣。不過 JDK 5.0 定義了5 個標準的 JDBC RowSet 介面,並且給出了相應的參考實現,因此可以很方便的使用RowSet介面所提供的功能。

   RowSet 物件可以建立一個與資料來源的連線並在其整個生命週期中維持該連線,在此情況下,該物件被稱為連線的 rowset。rowset 還可以建立一個與資料來源的連線,從其獲取資料,然後關閉它。這種 rowset 被稱為非連線 rowset。非連線 rowset 可以在斷開時更改其資料,然後將這些更改傳送回原始資料來源,不過它必須重新建立連線才能完成此操作。 相比較java.sql.ResultSet 而言,RowSet 的離線操作能夠有效的利用計算機越來越充足的記憶體,減輕資料庫伺服器的負擔,由於資料操作都是在記憶體中進行然後批量提交到資料來源,靈活性和效能都有了很大的提高。RowSet 預設是一個可滾動,可更新,可序列化的結果集,而且它作為 JavaBeans,可以方便地在網路間傳輸,用於兩端的資料同步。

1、與ResultSet比較

(1)RowSet擴充套件了ResultSet介面,因此可以像使用ResultSet一樣使用RowSet。

(2)RowSet擴充套件了ResultSet介面,因此功能比ResultSet更多、更豐富。

(3)預設情況下,所有 RowSet 物件都是可滾動的和可更新的。而ResultSet是隻能向前滾動和只讀的。

(4)RowSet可以是非連結的,而ResultSet是連線的。因此利用CacheRowSet介面可以離線運算元據。

(5)RowSet介面新增了對 JavaBeans 元件模型的 JDBC API 支援。rowset 可用作視覺化 Bean 開發環境中的 JavaBeans 元件。

(6)RowSet採用了新的連線資料庫的方法。

(7)CacheRowSet是可以序列化的。

(8)RowSet和ResultSet都代表一行行的資料、屬性以及相關操作方法。

(9)自己認為,應該傾向於把RowSet看成是與資料庫無關的東西,它只是一個代表一行行資料的物件,而ResultSet則是一個與資料庫緊密聯絡的東西。

2、JDK 5.0 的5個標準RowSet介面

在JDK 5.0中,5個標準RowSet介面包括 CachedRowSet,WebRowSet,FilteredRowSet,JoinRowSet 和 JdbcRowSet。相應的參考實現是Sun公司給出的,位於com.sun.rowset包下,分別為為CachedRowSetImpl,WebRowSetImpl,FilteredRowSetImpl,JoinRowSetImpl 和 JdbcRowSetImpl。這5個標準介面中JdbcRowSet是連結的rowset,而其他4個是非連結的rowset。

(1)CachedRowSet:最常用的一種 RowSet。其他三種 RowSet(WebRowSet,FilteredRowSet,JoinRowSet)都是直接或間接繼承於它並進行了擴充套件。它提供了對資料庫的離線操作,可以將資料讀取到記憶體中進行增刪改查,再同步到資料來源。CachedRowSet是可滾動的、可更新的、可序列化,可作為 JavaBeans 在網路間傳輸。支援事件監聽,分頁等特性。 CachedRowSet 物件通常包含取自結果集的多個行,但是也可包含任何取自表格式檔案(如電子表格)的行。

(2)WebRowSet:繼承自 CachedRowSet,並可以將 WebRowSet 寫到 XML 檔案中,也可以用符合規範的 XML 檔案來填充 WebRowSet。

(3)FilteredRowSet:通過設定 Predicate(在 javax.sql.rowset 包中),提供資料過濾的功能。可以根據不同的條件對 RowSet 中的資料進行篩選和過濾。

(4)JoinRowSet:提供類似 SQL JOIN 的功能,將不同的 RowSet 中的資料組合起來。目前在 Java 6 中只支援內聯(Inner Join)。

(5)JdbcRowSet:對 ResultSet 的一個封裝,使其能夠作為 JavaBeans 被使用,是唯一一個保持資料庫連線的 RowSet。JdbcRowSet 物件是連線的 RowSet 物件,也就是說,它必須使用啟用 JDBC 技術的驅動程式(“JDBC 驅動程式”)來持續維持它與資料來源的連線。

3、填充RowSet

前面說過,應該傾向於把RowSet看成是與資料庫無關而只代表一行行資料的物件,因此就涉及到資料從哪裡來的問題。

(1)從資料庫直接獲取資料

由於大部分情況下,與資料打交道也就是與資料庫打交道,因此RowSet介面提供了通過JDBC直接從資料庫獲取資料的方法,以參考實現JdbcRowSetImpl為例,就是這樣:

   RowSet rs = new JdbcRowSetImpl(); //也可以是CachedRowSetImpl,WebRowSetImpl,FilteredRowSetImpl,JoinRowSetImpl。
   rs.setUrl("jdbc:mysql:///test");
   rs.setUsername("root");
   rs.setPassword("");
   rs.setCommand("SELECT * FROM EMPLOYEES");
   rs.execute();

設定好相關屬性,執行execute()方法後,EMPLOYEES表中的資料就被填充到rs物件中了。
除了通過設定JDBC連線URL、使用者名稱和密碼外,RowSet也可以使用資料來源名稱屬性的值來查詢已經在命名服務中註冊的 DataSource 物件。完成檢索後,可以使用 DataSource 物件建立到它所表示的資料來源的連線,設定資料來源名稱可以使用setDataSourceName()方法。

(2)用ResultSet填充

在有現成ResultSet的情況下,如果想將其作為RowSet使用;或者當 DBMS 不提供對滾動和更新的完全支援時,如果想使不可滾動和只讀的 ResultSet 物件變得可滾動和可更新,可以建立一個使用該 ResultSet 物件的資料所填充的 CachedRowSet 物件。

ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES");
   CachedRowSet crs = new CachedRowSetImpl(); //也可以是WebRowSetImpl,FilteredRowSetImpl,JoinRowSetImpl,因為他們均繼承自CachedRowSetImpl
   crs.populate(rs);

執行populate()方法後,ResultSet物件rs中的資料就被填充到crs物件中了。

(3)用XML填充

如果您打算將XML作為資料交換格式在客戶端和你的伺服器之間傳輸資料並且向實現資料離線編輯、或者向使用XML格式的資料的話,可以使用WebRowSet介面來用XML填充資料。

   WebRowSet wrs = new WebRowSetImpl();
   wrs.readXml(new FileReader(new File("D:\\employees.xml")));

執行readXml()方法後,employees.xml檔案的資料就被填充到wrs物件中了。employees.xml 檔案的格式參見附錄。

(4)用其他方法填充

如果形用其他方式填充,比如csv、excel、text、http等格式或方法填充資料,那麼就需要自己編寫程式碼實現RowSet。

4、操作RowSet中的資料及後設資料

除了ResultSet提供的運算元據和後設資料方法外,RowSet介面沒有提供太多額外的方法。

1)更新資料
   rs.absolute(5);
   rs.updateInt(1, 10);
   rs.updateInt(2, 1000);
   rs.updateString(3, "John");
   rs.updateRow();


(2)插入資料
   rs.moveToInsertRow();
   rs.updateInt(1, 10);
   rs.updateInt(2, 1000);
   rs.updateString(3, "John");
   rs.insertRow();


(3)刪除資料
   rs.absolute(5);
   rs.deleteRow();


(4)設定屬性
   rs.setCommand("select id, salary, name from employees where id = ?");
   rs.setInt(1, 1);
   rs.execute();


(5)後設資料
   RowSetMetaData rsmd = (RowSetMetaData)rs.getMetaData();
   int count = rsmd.getColumnCount();
   int type = rsmd.getColumnType(2);
   
5、事務與更新底層資料來源

RowSet本身只代表具體資料,事務以及底層資料來源的更新是與底層資料來源密切相關的概念。對於JDBC資料來源,相應的標準介面JdbcRowSet通過與資料庫相關的方法來來實現,如commit(),rollback()等。對於標準介面的中非連線rowset,如CachedRowSet,則在對RowSet中的資料改動後,通過執行acceptChanges()方法,在內部呼叫 RowSet 物件的 writer 將這些更改寫入資料來源,從而將 CachedRowSet 物件中的更改傳播回底層資料來源。

6、可序列化非連線RowSet

使用 CachedRowSet 物件的主要原因之一是要在應用程式的不同元件之間傳遞資料。因為 CachedRowSet 物件是可序列化的,所以可使用它(舉例來說)將執行於伺服器環境的企業 JavaBeans 元件執行查詢的結果通過網路傳送到執行於 web 瀏覽器的客戶端。

由於 CachedRowSet 物件是非連線的,所以和具有相同資料的 ResultSet 物件相比更為簡潔。因此,它特別適於向瘦客戶端(如 PDA)傳送資料,這種瘦客戶端由於資源限制或安全考慮而不適於使用 JDBC 驅動程式。所以 CachedRowSet 物件可提供一種“獲取各行”的方式而無需實現全部 JDBC API。

ebRowSet繼承自CachedRowSet,除了擁有CachedRowSet的優點外,還可以將WebRowSet輸出成XML,也可以將XML轉換成WebRowSet,更加適合在Web環境中使用。標準的 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")));

附:employees.xml

<?xml version="1.0"?>
<webRowSet xmlns="
http://java.sun.com/xml/ns/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/jdbc http://java.sun.com/xml/ns/jdbc/webrowset.xsd">
<properties>
    <command>select id, salary, name from employees</command>
    <concurrency>1008</concurrency>
    <datasource><null/></datasource>
    <escape-processing>true</escape-processing>
    <fetch-direction>1000</fetch-direction>
    <fetch-size>0</fetch-size>
    <isolation-level>2</isolation-level>
    <key-columns>
    </key-columns>
    <map>
    </map>
    <max-field-size>0</max-field-size>
    <max-rows>0</max-rows>
    <query-timeout>0</query-timeout>
    <read-only>true</read-only>
    <rowset-type>ResultSet.TYPE_SCROLL_INSENSITIVE</rowset-type>
    <show-deleted>false</show-deleted>
    <table-name>employees</table-name>
    <url>jdbc:mysql:///test</url>
    <sync-provider>
      <sync-provider-name>com.sun.rowset.providers.RIOptimisticProvider</sync-provider-name>
      <sync-provider-vendor>Sun Microsystems Inc.</sync-provider-vendor>
      <sync-provider-version>1.0</sync-provider-version>
      <sync-provider-grade>2</sync-provider-grade>
      <data-source-lock>1</data-source-lock>
    </sync-provider>
</properties>
<metadata>
    <column-count>3</column-count>
    <column-definition>
      <column-index>1</column-index>
      <auto-increment>false</auto-increment>
      <case-sensitive>false</case-sensitive>
      <currency>false</currency>
      <nullable>0</nullable>
      <signed>true</signed>
      <searchable>true</searchable>
      <column-display-size>11</column-display-size>
      <column-label>id</column-label>
      <column-name>id</column-name>
      <schema-name></schema-name>
      <column-precision>11</column-precision>
      <column-scale>0</column-scale>
      <table-name>employees</table-name>
      <catalog-name>test</catalog-name>
      <column-type>4</column-type>
      <column-type-name>INT</column-type-name>
    </column-definition>
    <column-definition>
      <column-index>2</column-index>
      <auto-increment>false</auto-increment>
      <case-sensitive>false</case-sensitive>
      <currency>false</currency>
      <nullable>1</nullable>
      <signed>true</signed>
      <searchable>true</searchable>
      <column-display-size>11</column-display-size>
      <column-label>salary</column-label>
      <column-name>salary</column-name>
      <schema-name></schema-name>
      <column-precision>11</column-precision>
      <column-scale>0</column-scale>
      <table-name>employees</table-name>
      <catalog-name>test</catalog-name>
      <column-type>4</column-type>
      <column-type-name>INT</column-type-name>
    </column-definition>
    <column-definition>
      <column-index>3</column-index>
      <auto-increment>false</auto-increment>
      <case-sensitive>false</case-sensitive>
      <currency>false</currency>
      <nullable>1</nullable>
      <signed>false</signed>
      <searchable>true</searchable>
      <column-display-size>25</column-display-size>
      <column-label>name</column-label>
      <column-name>name</column-name>
      <schema-name></schema-name>
      <column-precision>25</column-precision>
      <column-scale>0</column-scale>
      <table-name>employees</table-name>
      <catalog-name>test</catalog-name>
      <column-type>12</column-type>
      <column-type-name>VARCHAR</column-type-name>
    </column-definition>
</metadata>
<data>
    <currentRow>
      <columnValue>1</columnValue>
      <columnValue>1000</columnValue>
      <columnValue>John</columnValue>
    </currentRow>
    <currentRow>
      <columnValue>2</columnValue>
      <columnValue>1200</columnValue>
      <columnValue>Tom</columnValue>
    </currentRow>
</data>
</webRowSet>

 

相關文章