这些Java教程是针对JDK 8编写的。本页中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
请参阅Java语言更改,了解Java SE 9及其后续版本中更新的语言功能的摘要。
请参阅JDK发行说明,了解有关所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息。
一个 WebRowSet 对象非常特殊,因为除了提供所有 CachedRowSet 对象的功能外,它还可以将自己写入一个 XML 文档,并且可以读取该 XML 文档将自己转换回 WebRowSet 对象。由于 XML 是不同企业之间可以相互通信的语言,因此它已成为 Web 服务通信的标准。因此,WebRowSet 对象通过以 XML 文档的形式使 Web 服务能够发送和接收来自数据库的数据,填补了一个真正的需求。
下面是所涵盖的主题:
Coffee Break 公司已扩展到在线销售咖啡。用户从 Coffee Break 网站按磅订购咖啡。价格列表通过从公司数据库中获取最新信息定期更新。本节演示如何通过使用 WebRowSet 对象和单个方法调用将价格数据作为 XML 文档发送。
您可以使用 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文档中发送最新价格清单的方法。
价格清单由来自表COFFEES的COF_NAME和PRICE列的数据组成。以下代码片段设置所需的属性,并使用价格清单数据填充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_NAME和PRICE列的数据,以及关于这两列的元数据。
要将WebRowSet对象写入XML文档,调用writeXml方法。要将该XML文档的内容读取到WebRowSet对象中,调用readXml方法。这两个方法在后台完成其工作,除了结果之外,其他都对您不可见。
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对象。在下面的代码行中,方法writeXml将ResultSet对象rs的内容读取到priceList对象中,然后将priceList作为XML文档写入FileOutputStream对象oStream。
priceList.writeXml(rs, oStream);
在下一行代码中,writeXml方法将priceList填充为rs的内容,但是它将XML文档写入FileWriter对象而不是OutputStream对象:
priceList.writeXml(rs, writer);
方法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文档将包含的内容以及必须呈现的格式。发送方和接收方都使用此模式,因为它告诉发送方如何编写表示WebRowSet对象的XML文档,以及接收方如何解析XML文档。由于writeXml和readXml方法的实现内部进行实际的写入和读取,作为用户,您不需要了解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对象。此外,username和password属性没有列出,因为它们必须保持机密。
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列中的值,你可以使用getString或updateString方法,驱动程序会进行到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>
您可以像对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>
示例WebRowSetSample.java演示了本页面描述的所有功能。