# 使用 WebRowSet 对象
> 原文: [https://docs.oracle.com/javase/tutorial/jdbc/basics/webrowset.html](https://docs.oracle.com/javase/tutorial/jdbc/basics/webrowset.html)
`WebRowSet`对象非常特殊,因为除了提供`CachedRowSet`对象的所有功能外,它还可以将自身编写为 XML 文档,还可以读取该 XML 文档以将其自身转换回`WebRowSet`对象。由于 XML 是不同企业可以相互通信的语言,因此它已成为 Web 服务通信的标准。因此,`WebRowSet`对象通过使 Web 服务能够以 XML 文档的形式从数据库发送和接收数据来满足实际需求。
涵盖以下主题:
* [创建和填充 WebRowSet 对象](#creating-and-populating-webrowset-object)
* [编写和读取 WebRowSet 对象到 XML](#writing-and-reading-webrowset-object-to-xml)
* [XML 文档中有什么](#what-is-in-xml-document)
* [对 WebRowSet 对象进行更改](#making-changes-to-webrowset-object)
Coffee Break 公司已经扩展到在线销售咖啡。用户从 Coffee Break 网站点击咖啡。通过从公司数据库获取最新信息,定期更新价目表。本节演示如何使用`WebRowSet`对象和单个方法调用将价格数据作为 XML 文档发送。
使用参考实现`WebRowSetImpl`中定义的默认构造器创建新的`WebRowSet`对象,如以下代码行所示:
```
WebRowSet priceList = new WebRowSetImpl();
```
虽然`priceList`对象尚无数据,但它具有`BaseRowSet`对象的默认属性。它的`SyncProvider`对象首先设置为`RIOptimisticProvider`实现,这是所有断开连接的`RowSet`对象的默认设置。但是,`WebRowSet`实现将`SyncProvider`对象重置为`RIXMLProvider`实现。
您可以使用`RowSetProvider`类创建的`RowSetFactory`实例来创建`WebRowSet`对象。有关详细信息,请参阅[使用](jdbcrowset.html#rowsetfactory)[中的 RowSetFactory 接口](jdbcrowset.html)使用 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-webrowset)
* [元数据](#metadata-webrowset)
* [数据](#data-webrowset)
元素标签用信号通知元素的开头和结尾。例如,`<properties>`标记表示属性元素的开头,`</properties>`标记表示其结束。 `<map/>`标签是说明地图子元素(属性元素中的一个子元素)尚未赋值的简写方式。以下示例 XML 文档使用间距和缩进来使其更易于阅读,但这些不在实际的 XML 文档中使用,其中间距并不意味着什么。
接下来的三节将向您展示在样例 [`WebRowSetSample.java`](gettingstarted.html) 中创建的`WebRowSet` `priceList`对象的三个主要元素。
在`priceList`对象上调用方法`writeXml`将生成描述`priceList`的 XML 文档。此 XML 文档的属性部分如下所示:
```
select COF_NAME, PRICE from COFFEES
1008
true
1000
0
2
1
0
0
0
true
ResultSet.TYPE_SCROLL_INSENSITIVE
false
COFFEES
jdbc:mysql://localhost:3306/testdb
com.sun.rowset.providers.RIOptimisticProvider
Sun Microsystems Inc.
1.0
2
1
```
请注意,某些属性没有任何价值。例如,`datasource`属性用`<datasource/>`标签表示,这是说`<datasource></datasource>`的简写方式。没有给出值,因为设置了`url`属性。建立的任何连接都将使用此 JDBC URL 完成,因此不需要设置`DataSource`对象。此外,未列出`username`和`password`属性,因为它们必须保密。
描述`WebRowSet`对象的 XML 文档的元数据部分包含有关该`WebRowSet`对象中的列的信息。以下显示了`WebRowSet`对象`priceList`的这一部分。因为`priceList`对象有两列,所以描述它的 XML 文档有两个`<column-definition>`元素。每个`<column-definition>`元素都有子元素,提供有关所描述列的信息。
```
2
1
false
false
false
0
false
true
32
COF_NAME
COF_NAME
32
0
coffees
testdb
12
VARCHAR
2
false
true
false
0
true
true
12
PRICE
PRICE
10
2
coffees
testdb
3
DECIMAL
```
从此元数据部分,您可以看到每行中有两列。第一列是`COF_NAME`,其中包含`VARCHAR`类型的值。第二列是`PRICE`,它保存`REAL`类型的值,依此类推。请注意,列类型是数据源中使用的数据类型,而不是 Java 编程语言中的类型。要获取或更新`COF_NAME`列中的值,可以使用方法`getString`或`updateString`,驱动程序会像往常一样转换为`VARCHAR`类型。
数据部分给出`WebRowSet`对象每行中每列的值。如果已填充`priceList`对象并且未对其进行任何更改,则 XML 文档的数据元素将如下所示。在下一节中,您将看到在修改`priceList`对象中的数据时 XML 文档如何更改。
对于每一行,都有一个`<currentRow>`元素,因为`priceList`有两列,每个`<currentRow>`元素包含两个`<columnValue>`元素。
```
Colombian
7.99
Colombian_Decaf
8.99
Espresso
9.99
French_Roast
8.99
French_Roast_Decaf
9.99
```
您对`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>`元素看起来类似于以下内容。
```
Kona
8.99
```
## 删除行
店主决定 Espresso 销售不足,应该从咖啡休息店出售的咖啡中取出。因此,所有者想要从价目表中删除 Espresso。 Espresso 位于`priceList`对象的第三行,因此以下代码行将其删除:
```
priceList.absolute(3); priceList.deleteRow();
```
以下`<deleteRow>`元素将出现在 XML 文档的数据部分中的第二行之后,表示已删除第三行。
```
Espresso
9.99
```
## 修改行
店主进一步决定哥伦比亚咖啡的价格过于昂贵,并希望将其降低至每磅 6.99 美元。以下代码将哥伦比亚咖啡的新价格设定为每磅 6.99 美元,这是第一排的价格:
```
priceList.first();
priceList.updateFloat(PRICE, 6.99);
```
XML 文档将在提供新值的`<updateRow>`元素中反映此更改。第一列的值没有改变,因此只有第二列的`<updateValue>`元素:
```
Colombian
7.99
6.99
```
此时,通过插入行,删除行以及修改行,`priceList`对象的 XML 文档如下所示:
```
Kona
8.99
Colombian
7.99
6.99
Colombian_Decaf
8.99
Espresso
9.99
French_Roast
8.99
French_Roast_Decaf
9.99
```
## WebRowSet 代码示例
示例 `[WebRowSetSample.java](gettingstarted.html)`演示了此页面上描述的所有功能。