这些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
演示了本页面描述的所有功能。