使用 WebRowSet 对象
原文: https://docs.oracle.com/javase/tutorial/jdbc/basics/webrowset.html
WebRowSet
对象非常特殊,因为除了提供CachedRowSet
对象的所有功能外,它还可以将自身编写为 XML 文档,还可以读取该 XML 文档以将其自身转换回WebRowSet
对象。由于 XML 是不同企业可以相互通信的语言,因此它已成为 Web 服务通信的标准。因此,WebRowSet
对象通过使 Web 服务能够以 XML 文档的形式从数据库发送和接收数据来满足实际需求。
涵盖以下主题:
Coffee Break 公司已经扩展到在线销售咖啡。用户从 Coffee Break 网站点击咖啡。通过从公司数据库获取最新信息,定期更新价目表。本节演示如何使用WebRowSet
对象和单个方法调用将价格数据作为 XML 文档发送。
使用参考实现WebRowSetImpl
中定义的默认构造器创建新的WebRowSet
对象,如以下代码行所示:
WebRowSet priceList = new WebRowSetImpl();
虽然priceList
对象尚无数据,但它具有BaseRowSet
对象的默认属性。它的SyncProvider
对象首先设置为RIOptimisticProvider
实现,这是所有断开连接的RowSet
对象的默认设置。但是,WebRowSet
实现将SyncProvider
对象重置为RIXMLProvider
实现。
您可以使用RowSetProvider
类创建的RowSetFactory
实例来创建WebRowSet
对象。有关详细信息,请参阅使用中的 RowSetFactory 接口使用 JdbcRowSet 对象。
Coffee Break 总部定期向其网站发送价目表更新。有关WebRowSet
对象的信息将显示一种可以在 XML 文档中发送最新价目表的方法。
价格表包含表COFFEES
中COF_NAME
和PRICE
列中的数据。以下代码片段设置所需的属性,并使用价目表数据填充priceList
对象:
public void getPriceList(String username, String password) {
priceList.setCommand("SELECT COF_NAME, PRICE FROM COFFEES");
priceList.setURL("jdbc:mySubprotocol:myDatabase");
priceList.setUsername(username);
priceList.setPassword(password);
priceList.execute();
// ...
}
此时,除了默认属性外,priceList
对象还包含COFFEES
表中COF_NAME
和PRICE
列中的数据以及有关这两列的元数据。
要将WebRowSet
对象写为 XML 文档,请调用方法writeXml
。要将 XML 文档的内容读入WebRowSet
对象,请调用方法readXml
。这两种方法都在后台完成它们的工作,这意味着除了结果之外的所有内容对您来说都是不可见的。
使用 writeXml 方法
方法writeXml
将调用它的WebRowSet
对象写为表示其当前状态的 XML 文档。它将此 XML 文档写入您传递给它的流。流可以是OutputStream
对象,例如FileOutputStream
对象,或Writer
对象,例如FileWriter
对象。如果传递方法writeXml
和OutputStream
对象,则将以字节为单位写入,可以处理所有类型的数据;如果你传递一个Writer
对象,你将写入字符。以下代码演示了将WebRowSet
对象priceList
作为 XML 文档写入FileOutputStream
对象oStream
:
java.io.FileOutputStream oStream =
new java.io.FileOutputStream("priceList.xml");
priceList.writeXml(oStream);
以下代码将表示priceList
的 XML 文档写入FileWriter
对象writer
而不是OutputStream
对象。 FileWriter
类是用于将字符写入文件的便捷类。
java.io.FileWriter writer =
new java.io.FileWriter("priceList.xml");
priceList.writeXml(writer);
方法的另外两个版本writeXml
允许您在将ResultSet
对象的内容写入流之前使用ResultSet
对象的内容填充该对象。在下面的代码行中,方法writeXml
将ResultSet
对象rs
的内容读入priceList
对象,然后将priceList
作为 XML 文档写入FileOutputStream
对象oStream
。
priceList.writeXml(rs, oStream);
在下一行代码中,writeXml
方法使用rs
的内容填充priceList
,但它将 XML 文档写入FileWriter
对象而不是OutputStream
对象:
priceList.writeXml(rs, writer);
使用 readXml 方法
方法readXml
解析 XML 文档以构造 XML 文档描述的WebRowSet
对象。与方法writeXml
类似,您可以传递readXml
InputStream
对象或Reader
对象,从中读取 XML 文档。
java.io.FileInputStream iStream =
new java.io.FileInputStream("priceList.xml");
priceList.readXml(iStream);
java.io.FileReader reader = new
java.io.FileReader("priceList.xml");
priceList.readXml(reader);
请注意,您可以将 XML 描述读入新的WebRowSet
对象或调用writeXml
方法的相同WebRowSet
对象。在场景中,价格表信息从总部发送到网站,您将使用新的WebRowSet
对象,如以下代码行所示:
WebRowSet recipient = new WebRowSetImpl();
java.io.FileReader reader =
new java.io.FileReader("priceList.xml");
recipient.readXml(reader);
RowSet
对象不仅仅是它们包含的数据。它们还具有有关其列的属性和元数据。因此,表示WebRowSet
对象的 XML 文档除了其数据之外还包括该其他信息。此外,XML 文档中的数据包括当前值和原始值。 (回想一下原始值是在最近的数据更改之前存在的值。这些值是检查数据库中相应值是否已更改所必需的,从而产生了应该持久保存值的冲突:放入RowSet
对象的新值或其他人放入数据库的新值。)
WebRowSet XML Schema 本身就是一个 XML 文档,它定义了表示WebRowSet
对象的 XML 文档将包含的内容以及必须呈现它的格式。发件人和收件人都使用此架构,因为它告诉发件人如何编写 XML 文档(表示WebRowSet
对象)和收件人如何解析 XML 文档。因为实际的写入和读取是通过方法writeXml
和readXml
的实现在内部完成的,所以作为用户,您不需要了解 WebRowSet XML Schema 文档中的内容。
XML 文档包含分层结构中的元素和子元素。以下是描述WebRowSet
对象的 XML 文档中的三个主要元素:
元素标签用信号通知元素的开头和结尾。例如,<properties>
标记表示属性元素的开头,</properties>
标记表示其结束。 <map/>
标签是说明地图子元素(属性元素中的一个子元素)尚未赋值的简写方式。以下示例 XML 文档使用间距和缩进来使其更易于阅读,但这些不在实际的 XML 文档中使用,其中间距并不意味着什么。
接下来的三节将向您展示在样例 WebRowSetSample.java
中创建的WebRowSet
priceList
对象的三个主要元素。
在priceList
对象上调用方法writeXml
将生成描述priceList
的 XML 文档。此 XML 文档的属性部分如下所示:
<properties>
<command>
select COF_NAME, PRICE from COFFEES
</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>
1
</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>COFFEES</table-name>
<url>jdbc:mysql://localhost:3306/testdb</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>
请注意,某些属性没有任何价值。例如,datasource
属性用<datasource/>
标签表示,这是说<datasource></datasource>
的简写方式。没有给出值,因为设置了url
属性。建立的任何连接都将使用此 JDBC URL 完成,因此不需要设置DataSource
对象。此外,未列出username
和password
属性,因为它们必须保密。
描述WebRowSet
对象的 XML 文档的元数据部分包含有关该WebRowSet
对象中的列的信息。以下显示了WebRowSet
对象priceList
的这一部分。因为priceList
对象有两列,所以描述它的 XML 文档有两个<column-definition>
元素。每个<column-definition>
元素都有子元素,提供有关所描述列的信息。
<metadata>
2
1
<auto-increment>false</auto-increment>
<case-sensitive>false</case-sensitive>
<currency>false</currency>
<nullable>0</nullable>
<signed>false</signed>
<searchable>true</searchable>
32
COF_NAME
COF_NAME
<schema-name></schema-name>
32
0
<table-name>coffees</table-name>
<catalog-name>testdb</catalog-name>
12
VARCHAR
2
<auto-increment>false</auto-increment>
<case-sensitive>true</case-sensitive>
<currency>false</currency>
<nullable>0</nullable>
<signed>true</signed>
<searchable>true</searchable>
12
PRICE
PRICE
<schema-name></schema-name>
10
2
<table-name>coffees</table-name>
<catalog-name>testdb</catalog-name>
3
DECIMAL
</metadata>
从此元数据部分,您可以看到每行中有两列。第一列是COF_NAME
,其中包含VARCHAR
类型的值。第二列是PRICE
,它保存REAL
类型的值,依此类推。请注意,列类型是数据源中使用的数据类型,而不是 Java 编程语言中的类型。要获取或更新COF_NAME
列中的值,可以使用方法getString
或updateString
,驱动程序会像往常一样转换为VARCHAR
类型。
数据部分给出WebRowSet
对象每行中每列的值。如果已填充priceList
对象并且未对其进行任何更改,则 XML 文档的数据元素将如下所示。在下一节中,您将看到在修改priceList
对象中的数据时 XML 文档如何更改。
对于每一行,都有一个<currentRow>
元素,因为priceList
有两列,每个<currentRow>
元素包含两个<columnValue>
元素。
<data>
<currentRow>
Colombian
7.99
</currentRow>
<currentRow>
Colombian_Decaf
8.99
</currentRow>
<currentRow>
Espresso
9.99
</currentRow>
<currentRow>
French_Roast
8.99
</currentRow>
<currentRow>
French_Roast_Decaf
9.99
</currentRow>
</data>
您对WebRowSet
对象的更改方式与对CachedRowSet
对象的更改方式相同。但是,与CachedRowSet
对象不同,WebRowSet
对象会跟踪更新,插入和删除,以便writeXml
方法可以同时写入当前值和原始值。接下来的三个部分演示了对数据的更改,并显示了每次更改后描述WebRowSet
对象的 XML 文档的样子。您不必对 XML 文档做任何事情;对它的任何更改都是自动进行的,就像编写和读取 XML 文档一样。
插入行
如果 Coffee Break 连锁店的所有者想要在价目表中添加新咖啡,则代码可能如下所示:
priceList.absolute(3);
priceList.moveToInsertRow();
priceList.updateString(COF_NAME, "Kona");
priceList.updateFloat(PRICE, 8.99f);
priceList.insertRow();
priceList.moveToCurrentRow();
在参考实现中,紧接在当前行之后进行插入。在前面的代码片段中,当前行是第三行,因此新行将在第三行之后添加并成为新的第四行。为了反映这种插入,XML 文档将在<data>
元素中的第三个<currentRow>
元素之后添加以下<insertRow>
元素。
<insertRow>
元素看起来类似于以下内容。
<insertRow>
Kona
8.99
</insertRow>
删除行
店主决定 Espresso 销售不足,应该从咖啡休息店出售的咖啡中取出。因此,所有者想要从价目表中删除 Espresso。 Espresso 位于priceList
对象的第三行,因此以下代码行将其删除:
priceList.absolute(3); priceList.deleteRow();
以下<deleteRow>
元素将出现在 XML 文档的数据部分中的第二行之后,表示已删除第三行。
<deleteRow>
Espresso
9.99
</deleteRow>
修改行
店主进一步决定哥伦比亚咖啡的价格过于昂贵,并希望将其降低至每磅 6.99 美元。以下代码将哥伦比亚咖啡的新价格设定为每磅 6.99 美元,这是第一排的价格:
priceList.first();
priceList.updateFloat(PRICE, 6.99);
XML 文档将在提供新值的<updateRow>
元素中反映此更改。第一列的值没有改变,因此只有第二列的<updateValue>
元素:
<currentRow>
Colombian
7.99
<updateRow>6.99</updateRow>
</currentRow>
此时,通过插入行,删除行以及修改行,priceList
对象的 XML 文档如下所示:
<data>
<insertRow>
Kona
8.99
</insertRow>
<currentRow>
Colombian
7.99
<updateRow>6.99</updateRow>
</currentRow>
<currentRow>
Colombian_Decaf
8.99
</currentRow>
<deleteRow>
Espresso
9.99
</deleteRow>
<currentRow>
French_Roast
8.99
</currentRow>
<currentRow>
French_Roast_Decaf
9.99
</currentRow>
</data>
WebRowSet 代码示例
示例[WebRowSetSample.java]($docs-gettingstarted.html)
演示了此页面上描述的所有功能。