# 使用 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)

元素标签用信号通知元素的开头和结尾。例如，`&lt;properties&gt;`标记表示属性元素的开头，`&lt;/properties&gt;`标记表示其结束。 `&lt;map/&gt;`标签是说明地图子元素（属性元素中的一个子元素）尚未赋值的简写方式。以下示例 XML 文档使用间距和缩进来使其更易于阅读，但这些不在实际的 XML 文档中使用，其中间距并不意味着什么。

接下来的三节将向您展示在样本 [`WebRowSetSample.java`](gettingstarted.html) 中创建的`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`属性用`&lt;datasource/&gt;`标签表示，这是说`&lt;datasource&gt;&lt;/datasource&gt;`的简写方式。没有给出值，因为设置了`url`属性。建立的任何连接都将使用此 JDBC URL 完成，因此不需要设置`DataSource`对象。此外，未列出`username`和`password`属性，因为它们必须保密。

描述`WebRowSet`对象的 XML 文档的元数据部分包含有关该`WebRowSet`对象中的列的信息。以下显示了`WebRowSet`对象`priceList`的这一部分。因为`priceList`对象有两列，所以描述它的 XML 文档有两个`&lt;column-definition&gt;`元素。每个`&lt;column-definition&gt;`元素都有子元素，提供有关所描述列的信息。

```
<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 文档如何更改。

对于每一行，都有一个`&lt;currentRow&gt;`元素，因为`priceList`有两列，每个`&lt;currentRow&gt;`元素包含两个`&lt;columnValue&gt;`元素。

```
<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 文档将在`&lt;data&gt;`元素中的第三个`&lt;currentRow&gt;`元素之后添加以下`&lt;insertRow&gt;`元素。

`&lt;insertRow&gt;`元素看起来类似于以下内容。

```
<insertRow>
  Kona
  8.99
</insertRow>

```

## 删除行

店主决定 Espresso 销售不足，应该从咖啡休息店出售的咖啡中取出。因此，所有者想要从价目表中删除 Espresso。 Espresso 位于`priceList`对象的第三行，因此以下代码行将其删除：

```
priceList.absolute(3); priceList.deleteRow();

```

以下`&lt;deleteRow&gt;`元素将出现在 XML 文档的数据部分中的第二行之后，表示已删除第三行。

```
<deleteRow>
  Espresso
  9.99
</deleteRow>

```

## 修改行

店主进一步决定哥伦比亚咖啡的价格过于昂贵，并希望将其降低至每磅 6.99 美元。以下代码将哥伦比亚咖啡的新价格设定为每磅 6.99 美元，这是第一排的价格：

```
priceList.first();
priceList.updateFloat(PRICE, 6.99);

```

XML 文档将在提供新值的`&lt;updateRow&gt;`元素中反映此更改。第一列的值没有改变，因此只有第二列的`&lt;updateValue&gt;`元素：

```
<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](gettingstarted.html)`演示了此页面上描述的所有功能。