• 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)+"	"+
    53                         jdbcRs.getString(2)+"	"+
    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)+"	"+
    59             rs.getString(2)+"	"+
    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)+"	"
    64             +rs.getString(2)+"	"
    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行的记录,这就实现了分页。

  • 相关阅读:
    python作业堡垒机(第十三周)
    Python的一个BOX
    Nginx (限速)限制并发、限制访问速率、限制流量
    Nginx反向代理维基百科镜像制作全解析
    防盗链测试01
    Pycharm和IntelliJ IDEA激活 2017.3.x版本
    [Openwrt 扩展下篇] Openwrt搭建私有云Owncloud 9
    [Openwrt扩展中篇]添加Aria2和webui
    [Openwrt 扩展上篇]USB挂载&U盘启动&Samba共享
    python作业(第十一周)基于RabbitMQ rpc实现的主机管理
  • 原文地址:https://www.cnblogs.com/weststar/p/12704412.html
Copyright © 2020-2023  润新知