jdbc(RowSet離線結果集) – JAVA編程語言程序開發技術文章

jdbc(RowSet離線結果集)

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為例,就是這樣:
[java] 
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 對象。

[java] 
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填充數據。
[java] 
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 模式定義位於 URIhttps://java.sun.com/xml/ns/jdbc/webrowset.xsd。將WebRowSet保存為XML的代碼事例如下:

[java] 
wrs.setCommand("select id, salary, name from employees"); 
  wrs.execute();    
  wrs.writeXml(new FileWriter(new File("D:\\employees.xml"))); 

附:employees.xml
[html] 
<?xml version="1.0"?> 
<webRowSet xmlns="https://java.sun.com/xml/ns/jdbc" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="https://java.sun.com/xml/ns/jdbc https://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> 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。