文档

Java™ 教程
隐藏目录
使用WebRowSet对象
教程: JDBC数据库访问
课程: JDBC基础

使用WebRowSet对象

一个 WebRowSet 对象非常特殊,因为除了提供所有 CachedRowSet 对象的功能外,它还可以将自己写入一个 XML 文档,并且可以读取该 XML 文档将自己转换回 WebRowSet 对象。由于 XML 是不同企业之间可以相互通信的语言,因此它已成为 Web 服务通信的标准。因此,WebRowSet 对象通过以 XML 文档的形式使 Web 服务能够发送和接收来自数据库的数据,填补了一个真正的需求。

下面是所涵盖的主题:

Coffee Break 公司已扩展到在线销售咖啡。用户从 Coffee Break 网站按磅订购咖啡。价格列表通过从公司数据库中获取最新信息定期更新。本节演示如何通过使用 WebRowSet 对象和单个方法调用将价格数据作为 XML 文档发送。

创建和填充 WebRowSet 对象

您可以使用 RowSetProvider 类创建的 RowSetFactory 实例来创建一个新的 WebRowSet 对象。以下示例来自 WebRowSetSample.java

    RowSetFactory factory = RowSetProvider.newFactory();  
    try (WebRowSet priceList = factory.createWebRowSet();
         // ...
    ) {	  
      // ...

尽管 priceList 对象还没有数据,但它具有 BaseRowSet 对象的默认属性。它的 SyncProvider 对象最初设置为 RIOptimisticProvider 实现,这是所有断开连接的 RowSet 对象的默认值。然而,WebRowSet 实现将 SyncProvider 对象重置为 RIXMLProvider 实现。

您可以使用由 RowSetProvider 类创建的 RowSetFactory 实例来创建一个 WebRowSet 对象。有关更多信息,请参见 使用 RowSetFactory 接口中的使用 JdbcRowSet 对象

Coffee Break总部定期向其网站发送价格清单更新。这些关于WebRowSet对象的信息将展示一种在XML文档中发送最新价格清单的方法。

价格清单由来自表COFFEESCOF_NAMEPRICE列的数据组成。以下代码片段设置所需的属性,并使用价格清单数据填充priceList对象:

      int[] keyCols = {1};
      priceList.setUsername(settings.userName);
      priceList.setPassword(settings.password);
      priceList.setUrl(settings.urlString);
      priceList.setCommand("select COF_NAME, PRICE from COFFEES");
      priceList.setKeyColumns(keyCols);

      // 填充WebRowSet
      priceList.execute();

此时,除了默认属性外,priceList对象还包含来自COFFEES表的COF_NAMEPRICE列的数据,以及关于这两列的元数据。

将WebRowSet对象写入和读取为XML

要将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对象的内容填充WebRowSet对象。在下面的代码行中,方法writeXmlResultSet对象rs的内容读取到priceList对象中,然后将priceList作为XML文档写入FileOutputStream对象oStream

priceList.writeXml(rs, oStream);

在下一行代码中,writeXml方法将priceList填充为rs的内容,但是它将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);

XML文档中包含什么

RowSet对象不仅仅包含它们所包含的数据。它们还具有关于其列的属性和元数据。因此,表示WebRowSet对象的XML文档除了数据之外,还包括这些其他信息。此外,XML文档中的数据包括当前值和原始值。(回想一下,原始值是在最近对数据进行更改之前存在的值。这些值用于检查数据库中的相应值是否已更改,从而在新值放入RowSet对象还是其他人在数据库中放入新值之间创建冲突时,确定应该保持哪个值:)

WebRowSet XML Schema本身是一个XML文档,定义了表示WebRowSet对象的XML文档将包含的内容以及必须呈现的格式。发送方和接收方都使用此模式,因为它告诉发送方如何编写表示WebRowSet对象的XML文档,以及接收方如何解析XML文档。由于writeXmlreadXml方法的实现内部进行实际的写入和读取,作为用户,您不需要了解WebRowSet XML Schema文档中的内容。

XML文档以分层结构包含元素和子元素。以下是描述WebRowSet对象的XML文档中的三个主要元素:

元素标签表示元素的开始和结束。例如,<properties>标签表示属性元素的开始,</properties>标签表示其结束。<map/>标签是一种简写方式,表示map子元素(属性元素中的子元素之一)未分配值。下面的示例XML文档使用间距和缩进使其更易于阅读,但在实际的XML文档中,间距不具有任何意义。

接下来的三个部分将展示WebRowSet priceList对象的三个主要元素包含的内容,这些对象是在示例WebRowSetSample中创建的。

属性

调用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>
    <column>1</column>
  </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对象。此外,usernamepassword属性没有列出,因为它们必须保持机密。

元数据

XML文档中描述一个WebRowSet对象的元数据部分包含了关于该WebRowSet对象中的列的信息。以下展示了priceList这个WebRowSet对象的元数据部分的示例。因为priceList对象有两列,所以描述它的XML文档有两个<column-definition>元素。每个<column-definition>元素都有子元素,提供关于所描述列的信息。

<metadata>
  <column-count>2</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>false</signed>
    <searchable>true</searchable>
    <column-display-size>
      32
    </column-display-size>
    <column-label>COF_NAME</column-label>
    <column-name>COF_NAME</column-name>
    <schema-name></schema-name>
    <column-precision>32</column-precision>
    <column-scale>0</column-scale>
    <table-name>coffees</table-name>
    <catalog-name>testdb</catalog-name>
    <column-type>12</column-type>
    <column-type-name>
      VARCHAR
    </column-type-name>
  </column-definition>
  <column-definition>
    <column-index>2</column-index>
    <auto-increment>false</auto-increment>
    <case-sensitive>true</case-sensitive>
    <currency>false</currency>
    <nullable>0</nullable>
    <signed>true</signed>
    <searchable>true</searchable>
    <column-display-size>
      12
    </column-display-size>
    <column-label>PRICE</column-label>
    <column-name>PRICE</column-name>
    <schema-name></schema-name>
    <column-precision>10</column-precision>
    <column-scale>2</column-scale>
    <table-name>coffees</table-name>
    <catalog-name>testdb</catalog-name>
    <column-type>3</column-type>
    <column-type-name>
      DECIMAL
    </column-type-name>
  </column-definition>
</metadata>

从这个元数据部分可以看出,每一行有两列。第一列是COF_NAME,它保存了VARCHAR类型的值。第二列是PRICE,它保存了REAL类型的值,依此类推。需要注意的是,列的类型是数据源中使用的数据类型,而不是Java编程语言中的类型。要获取或更新COF_NAME列中的值,你可以使用getStringupdateString方法,驱动程序会进行到VARCHAR类型的转换,就像通常所做的那样。

数据

数据部分给出了WebRowSet对象中每一行中每一列的值。如果您已经填充了priceList对象并且没有对其进行任何更改,则XML文档的数据元素将如下所示。在接下来的部分中,您将看到当您修改priceList对象中的数据时,XML文档如何更改。

对于每一行,都有一个<currentRow>元素,因为priceList有两列,所以每个<currentRow>元素包含两个<columnValue>元素。

<data>
  <currentRow>
    <columnValue>哥伦比亚</columnValue>
    <columnValue>7.99</columnValue>
  </currentRow>
  <currentRow>
    <columnValue>
      哥伦比亚_无咖啡因
    </columnValue>
    <columnValue>8.99</columnValue>
  </currentRow>
  <currentRow>
    <columnValue>浓缩咖啡</columnValue>
    <columnValue>9.99</columnValue>
  </currentRow>
  <currentRow>
    <columnValue>法式烘焙</columnValue>
    <columnValue>8.99</columnValue>
  </currentRow>
  <currentRow>
    <columnValue>法式烘焙_无咖啡因</columnValue>
    <columnValue>9.99</columnValue>
  </currentRow>
</data>

修改WebRowSet对象

您可以像对CachedRowSet对象进行更改一样对WebRowSet对象进行更改。但是,与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>
  <columnValue>Kona</columnValue>
  <columnValue>8.99</columnValue>
</insertRow>

删除行

所有者认为 Espresso 销售不够好,应从 The Coffee Break 商店出售的咖啡中移除。因此,所有者希望从价格列表中删除 Espresso。Espresso 在 priceList 对象的第三行,因此以下代码将其删除:

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

以下的 <deleteRow> 元素将出现在 XML 文档的数据部分的第二行后面,表示第三行已被删除。

<deleteRow>
  <columnValue>Espresso</columnValue>
  <columnValue>9.99</columnValue>
</deleteRow>

修改行

所有者进一步决定哥伦比亚咖啡的价格太贵,希望将其降低到每磅 6.99 美元。以下代码将哥伦比亚咖啡的新价格设置为每磅 6.99 美元,它位于第一行:

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

XML 文档将在一个 <updateRow> 元素中反映此更改,并给出新值。第一列的值没有改变,因此只有第二列的 <updateValue> 元素:

<currentRow>
  <columnValue>Colombian</columnValue>
  <columnValue>7.99</columnValue>
  <updateRow>6.99</updateRow>
</currentRow>

到此为止,通过插入行、删除行和修改行,priceList 对象的 XML 文档将如下所示:

<data>
  <insertRow>
    <columnValue>Kona</columnValue>
    <columnValue>8.99</columnValue>
  </insertRow>
  <currentRow>
    <columnValue>Colombian</columnValue>
    <columnValue>7.99</columnValue>
    <updateRow>6.99</updateRow>
  </currentRow>
  <currentRow>
    <columnValue>
      Colombian_Decaf
    </columnValue>
    <columnValue>8.99</columnValue>
  </currentRow>
  <deleteRow>
    <columnValue>Espresso</columnValue>
    <columnValue>9.99</columnValue>
  </deleteRow>
  <currentRow>
    <columnValue>French_Roast</columnValue>
    <columnValue>8.99</columnValue>
  </currentRow>
  <currentRow>
    <columnValue>
      French_Roast_Decaf
    </columnValue>
    <columnValue>9.99</columnValue>
  </currentRow>
</data>

WebRowSet代码示例

示例WebRowSetSample.java演示了本页面描述的所有功能。


上一页: 使用 FilteredRowSet 对象
下一页: 使用高级数据类型