`
hjy2099
  • 浏览: 255263 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Java 6 RowSet 使用完全剖析(2)

    博客分类:
  • JAVA
阅读更多

分页

由于 CachedRowSet 是将数据临时存储在内存中,因此对于许多 SQL 查询,会返回大量的数据。如果将整个结果集全部存储在内存中会占用大量的内存,有时甚至是不可行的。对此 CachedRowSet 提供了分批从 ResultSet 中获取数据的方式,这就是分页。应用程序可以简单的通过 setPageSize 设置一页中数据的最大行数。也就是说,如果页大小设置为 5,一次只会从数据源获取 5 条数据。下面的代码示范了如何进行简单分页操作。(分页部分代码默认 ORDERS 表中有 10 条数据)

 

清单 11. 分页代码一

ResultSet rs = stmt.executeQuery(DBCreator.SQL_SELECT_ORDERS); 

CachedRowSet cachedRS = new CachedRowSetImpl(); // 设置页大小 

cachedRS.setPageSize(4); 

cachedRS.populate(rs, 1); 

while (cachedRS.nextPage()) { printRowSet(cachedRS); } 

while (cachedRS.previousPage()) { printRowSet(cachedRS); }  

 


可以看到只需要在 populate 之前使用 setPageSize 设置页的大小,就可以轻松实现分页了。每次调用 nextPage 或 previousPage 进行翻页后,行游标都会被自动移动到当前页第一行的前面,并且只能在当前页内移动。这样我们对每一页都可以像新的数据集一样进行遍历,非常方便。这里需要注意的是:

用来填充 CachedRowSet 的 ResultSet 必须是可滚动的(Scrollable)。
populate 必须使用有两个参数的版本,否则无法进行分页。读者可以将 cachedRS.populate(rs, 1); 换成 cachedRS.populate(rs); 看看会有怎样的情况发生。
ResultSet rs 必须在遍历完毕后才能关闭,否则翻页遍历时会抛 SQLException。
我们注意到在使用分页遍历数据集时,nextPage() 是最先被调用的,也就是说页与行相似,最开始的页游标是指向第 0 页的,通过 nextPage() 方法移到第一页,这样就可以用非常简洁的代码遍历数据集。那么如果在第 0 页时(第一次调用 nextPage)之前使用 next 遍历当前页会是怎样的结果呢?

 

清单 12. 分页代码二

ResultSet rs = stmt.executeQuery(DBCreator.SQL_SELECT_ORDERS); 

CachedRowSet cachedRS = new CachedRowSetImpl(); // 设置页大小 

cachedRS.setPageSize(4); 

cachedRS.populate(rs, 1); 

printRowSet(cachedRS); 

while (cachedRS.nextPage()) { 
    printRowSet(cachedRS); 
}  

 


我们看到第一页被输出了两次。也就是说使用 next 始终是可以遍历第一页的,而每次 nextPage 后,行游标都会被重置到当前页的第一行数据之前。对于使用 execute 填充数据的方式,通过 setPageSize 同样可以实现分页。

setMaxRows 可以设置 CachedRowSet 可遍历的最大行数。下面是 setMaxRows 和 setPageSize 同时使用的例子。

 

清单 13. 分页代码三

ResultSet rs = stmt.executeQuery(DBCreator.SQL_SELECT_ORDERS); 

CachedRowSet cachedRS = new CachedRowSetImpl(); 

cachedRS.setPageSize(4); 

cachedRS.setMaxRows(7); 

cachedRS.populate(rs, 1); 

while (cachedRS.nextPage()) { printRowSet(cachedRS); } 

rs.close();  

 

上面的例子中,分别将页大小设置为 4,最大行数设置为 7(设置页大小时,如果最大行数不等于 0,就必须小于等于最大行数),然后遍历打印所有行,输出如下。

清单 14. 清单 13 中的代码执行结果 The data in RowSet: 1 1 Book 2 1 Compute 3 2 Phone 4 2 Java The data in RowSet: 5 2 Test 6 1 C++ 7 2 Perl 


我们注意到,虽然满足 Select 条件的数据有 10 条,但由于我们使用 setMaxRows 设置了允许的最大行数,所以最终我们只得到了 7 条数据。另外 setPageSize 只会改变下一次填充页时的大小,无法影响当前页的大小。我们可以在数据填充完毕后再改变页的大小。

 

清单 15. 分页代码四

ResultSet rs = stmt.executeQuery(DBCreator.SQL_SELECT_ORDERS); 

CachedRowSet cachedRS = new CachedRowSetImpl(); 

cachedRS.setPageSize(4); 

cachedRS.populate(rs, 1); 

cachedRS.setPageSize(3); 

while (cachedRS.nextPage()) { printRowSet(cachedRS); } 

rs.close();

  


我们在 populate 数据之前设置的页大小是 4,在 populate 数据之后又将页大小设置为 3,然后遍历输出结果。

 

清单 16. 清单 15 中的代码执行结果

The data in RowSet: 1 1 Book 2 1 Compute 3 2 Phone 4 2 Java The data in RowSet: 5 2 Test 6 1 C++ 7 2 Perl The data in RowSet: 8 1 Ruby 9 1 Erlang 10 2 Python 


我们发现除了第一页有 4 条数据外,其余页都只有 3 条数据。实际上 populate 中就已经对第一页数据进行了填充,并且使用之前设置的 4 作为页大小。所以 populate 之后设置的页大小就只能从第二页开始起作用了。setMaxSize 与此相似,也是在每次填充页时计算。

应注意的问题

在 JDK 5.0 中,当删除一行中某列值为 null 时,会抛出 NullPointerException。例如,表 CUSTOMERS 中第二行第三列的值为 null。假设 cachedRS 里面填充着表 CUSTOMERS 的数据,那么下段代码在 JDK 5.0 下运行时会抛出 NullPointerException。在 JDK 6.0 中,此问题已得到修正。

 

清单 17.

cachedRS.absolute(2); 

cachedRS.deleteRow(); 

cachedRS.acceptChanges();  

 

使用 WebRowSet

WebRowSet 继承于 CachedRowSet,因此用来填充 CachedRowSet 的方式同样适用于 WebRowSet。WebRowSet 也可以读取一个符合规范的 XML 文件,填充自己。假定 CUSTOMERS.xml 是一个符合规范的 XML 文件,里面存放的是表 CUSTOMERS 的数据。

 

清单 18. 读取 XML 文件

WebRowSet newWebRS = new WebRowSetImpl(); 

newWebRS.readXml(new FileReader("CUSTOMERS.xml")); 

  

相比于 CachedRowSet,WebRowSet 就是添加了对 XML 文件读写的支持。它可以将自身数据输出到 XML 文件,也可以读取符合规范的 XML 文件,来填充自己。上段示例代码中已经演示了如何读取 XML 文件。如下示例代码则是生成一个 XML 文件。

 

清单 19. 生成 XML 文件

WebRowSet webRS = new WebRowSetImpl(); 

CachedRowSetDemo.fillRowSetWithExecute(webRS); // 输出到XML文件 

FileWriter fileWriter = new FileWriter("CUSTOMERS.xml"); 

webRS.writeXml(fileWriter);  

 


fillRowSetWithExecute(CachedRowSet) 是一个静态方法,它的功能是用表 CUSTOMERS 来填充传入的 CachedRowSet。

应注意的问题

按照规范,当一行被标记为更新时,在输出到 XML 文件时,应使用标签 <modifyRow>,但实际输出为 <currentRow>。
按照规范,当一行中某列被更新时,在输出到 XML 文件时,应使用标签 <updateValue>,但实际输出为 <updateRow>。
按照规范,读取 XML 文件时,如果某行标签为 <deleteRow>,在读到 WebRowSet 中时,该行应被标记为删除,实际读取后,状态丢失。
使用 FilteredRowSet

FilteredRowSet 继承自 WebRowSet。正如它的名字所示,FilteredRowSet 是一个带过滤功能的 RowSet。它的过滤规则在 Predicate 中定义。Predicate 也是 javax.sql.rowset 包下的接口,它定义了三个方法:boolean evaluate(Object value, int column),boolean evaluate(Object value, String columnName),boolean evaluate(RowSet rs)。 前两个方法主要是用来检查新插入行的值是否符合过滤规则,符合,返回 true;否则,返回 false。FilteredRowSet 在新插入行时,会用这个方法来检测。如果不符合,会抛出 SQLException。boolean evaluate(RowSet rs) 这个方法则是用来判断当前 RowSet 里面的所有数据,是否符合过滤规则。FilteredRowSet 在调用有关移动游标的方法时,会使用这个方法进行检测。只要符合过滤规则的数据才会显示出来。下面我们给出了一个非常简单的 Predicate 实现,它的过滤规则是每行第一列的值只有大于 1 的才是有效行。

 

清单 20. Rang.java

class Range implements Predicate 
{ 
    @Override public boolean evaluate(RowSet rs) 
    { 
         try { 
                   if (rs.getInt(1) > 1) 
                       { 
                            return true; 
                       } 
              } catch (SQLException e) { // do nothing } 
        return false; 
} 

    @Override public boolean evaluate(Object value, int column) throws SQLException { return false; } 

    @Override public boolean evaluate(Object value, String columnName) throws SQLException 
    { return false; } 
} 

 

下面这段代码演示了使用上面定义的 class Range 前后的数据变化。

 

清单 21.

 

FilteredRowSet filterRS = new FilteredRowSetImpl(); 
CachedRowSetDemo.fillRowSetWithExecute(filterRS); 
System.out.println("/*******Before set filter***********/"); 
CachedRowSetDemo.printRowSet(filterRS); 
System.out.println("\n/*******After set filter***********/"); 
Range range = new Range(); filterRS.setFilter(range); 
CachedRowSetDemo.printRowSet(filterRS);  

 
清单 22. 清单 21 中的代码执行结果

/*******Before set filter***********/

The data in RowSet: 1 Tom Tom is VIP. 2 Jim null

/*******After set filter***********/

The data in RowSet: 2 Jim null 

 

可以看出,在设置了过滤器后,再次打印 FilteredRowSet 中的数据时,由于第一行第一列的值为 1,不符合过滤规则,因此,没有打印出来。上面实现的这个 Predicate 中,用来检测新插入行是否符合过滤规则的方法直接返回 false。这样,在新插入行时,无论插入什么值时,都将抛出 SQLException。

 

应注意的问题

当设置了过滤器后,FilteredRowSet.absolute(1) 无论何时都返回 false。按照规范,如果第一行值不符合过滤规则,则移到第二行,依次类推,直到找到第一条符合过滤规则的结果行并返回 true,否则,返回 false。
在 JDK 5.0 下,如果 FilteredRowSet 没有设置过滤器,那么在新插入一行时会抛出 NullPointerException。在 JDK 6.0 中,已解决该问题。
使用 JdbcRowSet

JdbcRowSet 是对 ResultSet 的一个简单的封装,让它可以作为一个 JavaBeans 组件来使用。填充 JdbcRowSet 只能通过一种方式,即 execute() 方法。之后可以通过类似于操作 ResultSet 的方法来操作 JdbcRowSet。

 

清单 23.

JdbcRowSet JdbcRowSet jrs = new JdbcRowSetImpl(); 
jrs.setCommand(DBCreator.SQL_SELECT_CUSTOMERS); 
jrs.setUrl(DBCreator.DERBY_URL); 
jrs.execute(); 
while (jrs.next()) 
{ 
    for(int i = 1; i <= jrs.getMetaData().getColumnCount(); i++) 
   { 
       System.out.print(jrs.getObject(i) + " "); 
   } 
   System.out.println(); 
}  

 

分享到:
评论
1 楼 KimShen 2009-05-22  
在 JDK 5.0 中,当删除一行中某列值为 null 时,会抛出 NullPointerException。例如,表 CUSTOMERS 中第二行第三列的值为 null。假设 cachedRS 里面填充着表 CUSTOMERS 的数据,那么下段代码在 JDK 5.0 下运行时会抛出 NullPointerException。在 JDK 6.0 中,此问题已得到修正

我就用的jdk1.6 我怎么没发现修正了啊

相关推荐

    Java 6 RowSet 使用完全剖析

    Java 6 RowSet 使用完全剖析

    Java6RowSet使用完全剖析

    本文内容包括:RowSet简介类继承结构实验环境使用CachedRowSet使用WebRowSet使用FilteredRowSet使用JdbcRowSet使用JoinRowSet结束语下载参考资料C#提供了DataSet,可以将数据源中的数据读取到内存中,进行离线操作,...

    java的rowset工具包

    jdk虽然定义了jdbc中的rowset接口但是没有实现。如果想使用rowset就要倒入这个包。

    rowset

    sun对Rowset的实现

    rowset.jar

    支持CatchRowSet生成Excel报表

    rowset.jar下载

    rowset.jar下载rowset.jar下载rowset.jar下载rowset.jar下载rowset.jar下载rowset.jar下载

    ROWSET介绍加实例

    文档介绍了rowset的详细使用,并附有实例代码。

    rowset.jar包

    此处上传可以直接使用的rowset.jar包,直接下载放在包里,就可以使用了.

    java文集

    Java 6 RowSet 使用完全剖析 结合Spring2.0和ActiveMQ进行异步消息调用 struts+hibernate增删改查(一) AXIS 布署问题 struts+hibernate增删改查(二) MySQL中如何实现Top N及M至N段的记录查询?...

    sun.jdbc.rowset的jar包

    sun.jdbc.rowset的jar包,2000年的老包。不过有些老项目需要。 包括sun.jdbc.rowset.CachedRowSet。

    com.sun.rowset.jar.zip

    sun公司的rowset jar包。操作数据库很酷的

    sun.jdbc.rowset

    网上找了很多 下载下来都是com.sun.rowset 这个是正确的sun.jdbc.rowset

    JAVA_API1.6文档(中文)

    JavaTM 2 Platform Standard Edition 6 API 规范 本文档是 Java 2 Platform Standard Edition 6.0 的 API 规范。 请参见: 描述 Java 2 Platform 软件包 java.applet 提供创建 applet 所必需的类和 applet ...

    Java 1.6 API 中文 New

    JAVA开发人员必备!本文档是 Java Platform Standard Edition 6 的 API !Java 1.6 API的中文帮助文档。 深圳电信培训中心徐海蛟博士教学...org.omg.CORBA_2_3 CORBA_2_3 包定义对 Java[tm] Standard Edition 6 中现有...

    jdk1.4中无需修改的rowset.jar

    在jdk1.5上用spring管理数据,部署到jdk1.4上,说CachedRowSet有问题,寻遍方法,最后得一rowset对jdk1.4里的进行覆盖,得的rowset.jar还需要进行修改,于是修改好,放到项目的lib中,成功!想到需要帮助的人们,...

    java jdk实列宝典 光盘源代码

    6java异常处理 throw和throws、try和catch;自定义异常类;使用finally;使用异常的技巧和原则; 7 IO输入输出流 获取文件的基本信息;列出指定目录下的文件,并可过滤文件;创建文件和目录;删除文件和目录;移动...

    jdbc 帮助类 java 自带连接池 v1.01

    javax.sql.RowSet select(java.lang.String sql, java.util.Map&lt;java.lang.Integer,java.lang.Object&gt; elements) 执行单条查询语句,适用于简单的sql查询语句 javax.sql.RowSet select(java.lang.String sql, ...

    java7帮助文档

    The directory &lt;Java home&gt;/demo/jfc/Font2DTest/ contains samples that demonstrate Java support for Unicode 6.0. Java SE 7 can accommodate new currencies that are identified by their ISO 4217 codes; ...

    Java JDK实例宝典

    14 使用正则表达式验证电话号码的格式 第6章 Java异常处理 6. 1 throw. throws. try和catch 6. 2 自定义异常类 6. 3 使用finally 6. 4 使用异常的技巧与原则 第7章 IO——输入输出流 7...

Global site tag (gtag.js) - Google Analytics