10.7 使用RowSet 1.1B包装结果集

目录:

一、RowSetFactory与RowSet

二、离线RowSet

三、离线RowSet的查询分页

RowSet规范的接口示意图:

  除了JdbcRowSet需要保持与数据库保持连接之外,其余4个子接口都是离线的RowSet,无须保持与数据库的连接。

  与RowSet相比,RowSet默认是可滚动的、可更新的、可序列化的结果集,而且作为JavaBean使用,因此能方便在网络上传输,用于同步两端的数据。对于离线的RowSet而言,程序在创建RowSet时,已经把数据从底层数据库读取到内存,因此可以充分利用计算机内存,从而降低数据库服务器的负载,提高程序性能。

一、RowSetFactory与RowSet

Java 7新增RowSetProvider类和RowSetFactory接口,其中RowSetProvider负载创建RowSetFactory,而RowSetFactory则提供了如下方法来创建RowSet实例。

(1)CachedRowSet createCachedRowSet():创建一个默认的CachedRowSet。

(2)FilteredRowSet createFilteredRowSet():创建一个默认的FilteredRowSet。

(3)JdbcRowSet createJdbcRowSet():创建一个默认的JdbcRowSet。

(4)JoinRowSet createJoinRowSet():创建一个默认JoinRowSet。

(5)WebRowSet createWebRowSet():创建一个默认的WebRowSet。

通过RowSetFactory,就可以把应用程序与RowSet实现类分离开,避免直接使用JdbcRowSet SetImpl等非公开的API,也利于后期的升级、扩展。

 使用RowSetFactory创建的RowSet并没有创建装填数据。为了让RowSet能够抓取到数据库的数,需要为RowSet设置数据库的URL、用户名、密码等连接信息。因此,RowSet接口中定义了如下方法:
(1)setUrl(String url):设置RowSet要访问的数据库的URL。

(2)setUsername(String name):设置该RowSet要访问数据库的用户名。

(3)setPassword(String password):设置该RowSet要访问数据库的密码。

(4)setCommand(String sql):设置使用该sql语句查询结果来装填RowSet。

(5)excute():执行查询。

下面程序通过了RowSetFactory示范了JdbcRowSet的可滚动性、可修改性。

 1 package section6;
 2 
 3 import javax.sql.rowset.JdbcRowSet;
 4 import javax.sql.rowset.RowSetFactory;
 5 import javax.sql.rowset.RowSetProvider;
 6 import java.io.FileInputStream;
 7 import java.util.Properties;
 8 
 9 public class RowSetFactoryTest
10 {
11     private String driver;
12     private String url;
13     private String user;
14     private String pass;
15 
16     public void initParam(String fileName)
17             throws Exception
18     {
19         //使用Properties类加载属性
20         Properties props=new Properties();
21         props.load(new FileInputStream(fileName));
22         driver=props.getProperty("driver");
23         url=props.getProperty("url");
24         user=props.getProperty("user");
25         pass=props.getProperty("pass");
26     }
27 
28     public void updata(String sql)
29         throws Exception
30     {
31         //加载驱动
32         Class.forName(driver);
33         //使用RowSetProvider创建RowSetFactory
34         RowSetFactory factory= RowSetProvider.newFactory();
35         try(
36                 //使用RowSetFactory创建默认的JdbcRowSet实例
37                 JdbcRowSet jdbcRs=factory.createJdbcRowSet()
38                 )
39         {
40             //设置必要连接信息
41             jdbcRs.setUrl(url);
42             jdbcRs.setUsername(user);
43             jdbcRs.setPassword(pass);
44             //设置SQL查询语句
45             jdbcRs.setCommand(sql);
46             //执行结果
47             jdbcRs.execute();
48             jdbcRs.afterLast();
49             //先前滚动结果集
50             while(jdbcRs.previous())
51             {
52                 System.out.println(jdbcRs.getString(1)+"\t"+
53                         jdbcRs.getString(2)+"\t"+
54                         jdbcRs.getString(3));
55                 if(jdbcRs.getInt("student_id")==3)
56                 {
57                     //修改指定记录行
58                     jdbcRs.updateString("student_name","孙悟空");
59                     jdbcRs.updateRow();
60                 }
61             }
62         }
63     }
64     public static void main(String[] args)
65         throws Exception
66     {
67         var fac=new RowSetFactoryTest();
68         fac.initParam("src\\mysql.ini");
69         fac.updata("select *from student_table");
70 
71     }
72 }
View Code

 编译运行该程序,一切正常。JdbcRowSet是一个可滚动、可修改的结果集,因此底层的数据表中的记录也被修改了。

二、离线RowSet

在使用ResultSet时代,程序查询的得到ResultSet之后必须立即读取或处理它对应的记录,否则一旦Connection关闭,再通过ResultSet读取记录就会引发异常。假设应用程序架构分为两层:数据访问层和视图显示层,当应用程序在数据访问层查询得到ResultSet之后,对ResultSet的处理有如下两种常见方式:

·1、使用迭代访问ResultSet里的记录,并将这些记录转换成Java Bean,再将多个Java Bean封装成一个List集合,也就是完成“ResultSet—>Java Bean集合”的转换。转换完成后就可以关闭Connection等资源,然后将Java Bean集合传到视图显示层,视图显示层就可以显示查询得到的数据。

2、直接将ResultSet传到视图显示层——这就要求当视图显示层显示数据时,底层Connection必须一直处于打开状态,否则ResultSet无法读取记录。

第一种方式比较安全,但编程复杂;第二种方式则需要Connection一直处在打开状态,这不仅不安全,而且对程序性能影响大。

离线RowSet会直接将底层数据读入内存中,封装成RowSet对象,而RowSet对象则完全可以当成Java Bean来使用。因此不仅编安全,而且编程简单。CachedRowSet是所有离线RowSet的父接口,因此下面以CachedRowSet为例进行介绍:

 1 package section6;
 2 
 3 import javax.sql.rowset.CachedRowSet;
 4 import javax.sql.rowset.RowSetFactory;
 5 import javax.sql.rowset.RowSetProvider;
 6 import java.io.FileInputStream;
 7 import java.sql.*;
 8 import java.util.Properties;
 9 
10 public class CachedRowSetTest
11 {
12     private static String driver;
13     private static String url;
14     private static String user;
15     private static String pass;
16     public void initParam(String fileName)
17         throws Exception
18     {
19         //使用Properties类来加载属性
20         Properties props=new Properties();
21         props.load(new FileInputStream(fileName));
22         driver=props.getProperty("driver");
23         url=props.getProperty("url");
24         user=props.getProperty("user");
25         pass=props.getProperty("pass");
26     }
27     public CachedRowSet query(String sql)
28         throws Exception
29     {
30         //加载驱动
31         Class.forName(driver);
32         //获取数据库连接
33         Connection conn= DriverManager.getConnection(url,user,pass);
34         Statement stmt=conn.createStatement();
35         ResultSet rs=stmt.executeQuery(sql);
36         //使用RowSetProvider创建RowSetFactory
37         RowSetFactory factory= RowSetProvider.newFactory();
38         //创建默认的CachedRowSet实例
39         CachedRowSet cachedRs=factory.createCachedRowSet();
40         //使用ResultSet装填CachedRowSet
41         cachedRs.populate(rs);
42         //关闭资源
43         rs.close();
44         stmt.close();
45         conn.close();
46         return cachedRs;
47     }
48     public static  void main(String[] args)
49     throws Exception
50     {
51         var ct=new CachedRowSetTest();
52         ct.initParam("src\\mysql.ini");
53         CachedRowSet rs=ct.query("select *from student_table;");
54         rs.afterLast();
55         //向前滚动查询结果集
56         while(rs.previous())
57         {
58             System.out.println(rs.getString(1)+"\t"+
59             rs.getString(2)+"\t"+
60             rs.getString(3));
61             if(rs.getInt("student_id")==3)
62             {
63                 //修改指定记录行
64                 rs.updateString("student_name","孙悟空");
65                 rs.updateRow();
66             }
67         }
68         //重新获取数据库连接
69         Connection conn= DriverManager.getConnection(url,user,pass);
70         conn.setAutoCommit(false);
71         //把RowSet所做的修改同步到底层数据库
72         rs.acceptChanges(conn);
73     }
74 }
View Code

 上面代码调用了RowSet的populate(ResultSet rs)方法来包装给指定的ResultSet,接下来的关闭了ResultSet、Statement、Connection等数据库资源。如果程序直接返回ResultSet,那么这个ResultSet将无法使用——因为底层的Connection已经关闭:但程序返回的是CachedRowSet,它是一个离线的RowSet,因此程序依然可以读取、修改RowSet中的记录。

三、离线RowSet的查询分页

 由于CachedRowSet会将数据记录直接载入到内存中,因此如果SQL语句查询返回的记录过大,CachedRowSet会占用大量的内存,中某些极端情况下,它甚至会导致内存溢出。

为了解决上面的问题,CachedRowSet提供了分页功能——一次只装载ResultSet里的某几条记录,这样可以避免CachedRowSet占用内存过大的问题。

CachedRowSet提供如下方法控制分页:

1、populate(ResultSet rs,int starRow):使用给定ResultSet装填RowSet,从ResultSet里的第starRow条记录开始装填。

2、setPageSize(int pageSize):设置CachedRowSet每次返回多少条记录。

3、previousPage():在底层ResultSet可以的情况下,让CachedRowSet读取上一页记录。

4、nextPage():在底层ResultSet可以的情况下,让CachedRowSet读取下一页记录。

 1 package section6;
 2 
 3 import javax.sql.rowset.CachedRowSet;
 4 import javax.sql.rowset.RowSetFactory;
 5 import javax.sql.rowset.RowSetProvider;
 6 import java.io.FileInputStream;
 7 import java.sql.Connection;
 8 import java.sql.DriverManager;
 9 import java.sql.ResultSet;
10 import java.sql.Statement;
11 import java.util.Properties;
12 
13 public class CachedRowSetPage
14 {
15     private static String driver;
16     private static String url;
17     private static String user;
18     private static String pass;
19 
20     public void initParam(String fileName)
21             throws Exception
22     {
23         //使用Properties类来加载属性
24         Properties props=new Properties();
25         props.load(new FileInputStream(fileName));
26         driver=props.getProperty("driver");
27         url=props.getProperty("url");
28         user=props.getProperty("user");
29         pass=props.getProperty("pass");
30     }
31     public CachedRowSet query(String sql,int pageSize,int page)
32         throws Exception
33     {
34         //加载驱动
35         Class.forName(driver);
36         try(
37                 //获取数据库连接
38                 Connection conn= DriverManager.getConnection(url,user,pass);
39                 Statement stmt=conn.createStatement();
40                 ResultSet rs=stmt.executeQuery(sql)
41                 )
42         {
43             //  使用RowSetProvider创建RowSetFactory
44             RowSetFactory factory=RowSetProvider.newFactory();
45             //创建CachedRowSet实例
46             CachedRowSet cachedRs=factory.createCachedRowSet();
47             //设置每页显示pageSize条记录
48             cachedRs.setPageSize(pageSize);
49             //使用ResultSet装填RowSet,设置从第几条记录开始
50             cachedRs.populate(rs,(page-1)*pageSize+1);
51             return cachedRs;
52         }
53     }
54     public  static void main(String[] args)
55         throws Exception
56     {
57         var cp=new CachedRowSetPage();
58         cp.initParam("src\\mysql.ini");
59         CachedRowSet rs=cp.query("select *from student_table;",3,2);//60         //向后滚动结果集
61         while(rs.next())
62         {
63             System.out.println(rs.getString(1)+"\t"
64             +rs.getString(2)+"\t"
65             +rs.getString(3));
66         }
67     }
68 }
View Code

运行结果:

1 4    学生名4    2
2 5    学生名5    2
3 6    学生名6    2

程序①号带啊吗显示要查询第2页记录,每页显示3条记录。运行上面程序,可以看到程序只会显示第4行到第6行的记录,这就实现了分页。

猜你喜欢

转载自www.cnblogs.com/weststar/p/12704412.html