# 使用 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)`演示了此页面上描述的所有功能。