zoukankan      html  css  js  c++  java
  • Java JDBC结果集的处理

    结果集指针的移动

    while (resultSet.next()){
                //......
    }

    指针最初指向第一条记录之前,next()是指向下一个位置,返回的是boolean值,true表示有内容(记录),false表示无内容(false)。

    如果当前是指向最后一条记录,next()就指向最后一条记录之后,返回false,退出循环,遍历完成。

    准确地说,应该叫做游标(Cursor),学C++的时候叫指针(Pointer)叫习惯了......

    //下面3种都是相对当前位置的移动
            resultSet.next();  //指针移到下一个位置
            resultSet.previous();  //指针移到前一个位置
    
          resultSet.relative(2);  //相对当前位置后移2步
          resultSet.relative(-1);  //正数表示后移,负数表示前移。相对当前位置前移1步。
    
            //下面5种都是绝对位置的移动
           resultSet.absolute(n); //指向结果集中的第n+1条记录,n是下标,0表示第一条记录
    resultSet.first(); //指针移到第一条记录上 resultSet.last(); //指针移到最后一条记录上 resultSet.beforeFirst(); //指针移到第一条记录之前 resultSet.afterLast(); //指针移到最后一条记录之后 //对应的判断方法 resultSet.isFirst(); resultSet.isLast(); resultSet.isBeforeFirst(); resultSet.isAfterLast();

    获取结果集中的记录总数

    1     if(resultSet.last()) {   //指针移到最后一条记录上,使用if是因为结果集可能是空的,要先判断
    2            System.out.println(resultSet.getRow());  //getRow()是返回当前记录是结果集中的第几条记录,int型
    3     }

    离线查询

    如果要长期使用结果集中的数据,以前有2种方式:

    • 一直保持数据库连接,不关闭。如果保持的连接很多,服务器、数据库的性能都会受到影响。
    • 将结果集中的记录存储到多个JavaBean中,数据库没影响,但要编写JavaBean,写代码遍历结果集,将每行记录赋给JavaBean,自己写代码的话很麻烦。如果记录很多,创建大量的JavaBean是很花时间的,JVM要管理大量的JavaBean对象,开销很大,程序性能降低;且操作结果集比操作JavaBean的集合要简单。

    离线查询:在本地搞一个结果集的副本,关闭结果集、数据库连接,使用本地的这个副本。

    ResultSet接口有子接口RowSet,RowSet有子接口CachedRowSet。离线查询就是通过CachedRowSet来实现的。

     1 //从properties文件中加载数据库配置
     2         Properties properties = new Properties();
     3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
     4         properties.load(inputStream);
     5 
     6         String driver = properties.getProperty("driver");
     7         String url = properties.getProperty("url");
     8         String user = properties.getProperty("user");
     9         String pwd=properties.getProperty("password");
    10 
    11         Class.forName(driver);
    12         Connection connection = DriverManager.getConnection(url, user, pwd);
    13 
    14         String sql = "select * from student_tb";
    15         PreparedStatement preparedStatement = connection.prepareStatement(sql);
    16         ResultSet resultSet = preparedStatement.executeQuery();
    17 
    18         //离线查询
    19         RowSetFactory rowSetFactory = RowSetProvider.newFactory();  //通过RowSetProvider的静态方法创建RowSetFactory对象
    20         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();  //创建CachedRowSet对象
    21         cachedRowSet.populate(resultSet);  //使用结果集填充cachedRowSet
    22         //cachedRowSet.populate(resultSet,2);  //可指定从结果集的第几条记录开始填充,默认为1,从第一条记录开始填充
    23         
    24         //关闭数据库资源
    25         resultSet.close();  
    26         preparedStatement.close();  //关闭Statement|PreparedStatement对象
    27         connection.close();  
    28 
    29         //CachedRowSet是ResultSet的孙接口,继承了ResultSet的属性、方法,使用方式和ResultSet一样
    30         while(cachedRowSet.next()){
    31             int id = cachedRowSet.getInt("id");
    32             String name =cachedRowSet.getString("name");
    33             int age = cachedRowSet.getInt("age");
    34             float score = cachedRowSet.getFloat("score");
    35             System.out.println(id+"	"+name+"	"+age+"	"+score);
    36         }

    更新结果集

    ResultSet默认是可滚动的、不可更新的,不能删除、修改结果集中的记录。如果要获取可更新的结果集(可增删改结果集中的记录),需要在创建Statement | PreparedStatement对象时传入2个额外的参数。

    CachedRowSet默认是可滚动的、可更新的,可删除、修改CachedRowSet中的记录。

    可滚动指的是可以使用next()、first()、last()、absolute()等方法移动游标,不可滚动指的是只能使用next()来移动游标。

    可更新的ResultSet:

     1 //从properties文件中加载数据库配置
     2         Properties properties = new Properties();
     3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
     4         properties.load(inputStream);
     5 
     6         String driver = properties.getProperty("driver");
     7         String url = properties.getProperty("url");
     8         String user = properties.getProperty("user");
     9         String pwd=properties.getProperty("password");
    10 
    11         Class.forName(driver);
    12         Connection connection = DriverManager.getConnection(url, user, pwd);
    13 
    14         String sql = "select * from student_tb";
    15         /*
    16         获取可更新的结果集
    17 
    18         第二个参数指定结果集是否是可滚动的:
    19         ResultSet.TYPE_FORWARD_ONLY   不可滚动,只能使用next()移动游标
    20         ResultSet.TYPE_SCROLL_SENSITIVE  可滚动,底层数据的变化会同步到结果集(需要底层数据库驱动的支持)
    21         ResultSet.TYPE_SCROLL_INSENSITIVE  可滚动,底层数据的变化不会同步到结果集
    22 
    23         第三个参数指定结果集是否是可更新的:
    24         ResultSet.CONCUR_READ_ONLY   默认值,只读
    25         ResultSet.CONCUR_UPDATABLE   可更新(对结果集中的记录可增删改)
    26          */
    27         PreparedStatement preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    28         ResultSet resultSet = preparedStatement.executeQuery();
    29 
    30         while (resultSet.next()){
    31             int id = resultSet.getInt("id");
    32             if(id==5){
    33                 //updateXxx()修改当前记录某个字段的值,第一个参数指定列(字段),可以用列名或列索引,第二个参数指定新值
    34                 resultSet.updateString("name","chy");  //修改当前记录的name字段的值为chy
    35                 resultSet.updateRow();  //将对结果集中记录的改同步到数据库中,改不会自动同步到数据库中,需要手动同步
    36             }
    37             else if(id==10){
    38                 resultSet.deleteRow();  //删除当前记录(删除当前行),删会自动同步到数据库中
    39             }
    40         }
    41 
    42         //往结果集中插入一行
    43         resultSet.moveToInsertRow();  
    44         /*
    45         通过updateXxx()设置插入行的字段值
    46 
    47         resultSet.updateInt("id",100);
    48         如果不设置主键列(id)的值,默认插到结果集的末尾,
    49         如果结果集中没有id=100的记录,但数据库中有,同步到数据库时会出错
    50          */
    51         resultSet.updateString("name","CoCo");
    52         resultSet.updateInt("age",20);
    53         resultSet.updateInt("score",90);
    54 
    55         resultSet.insertRow();  //将增同步到数据库
    56 
    57         //这期间需要保持数据库连接
    58         
    59         resultSet.close();
    60         preparedStatement.close();
    61         connection.close();

    update、insert需要手动同步,delete却是自动同步,why?

    因为delete是一步操作,update、insert均是多步操作,update可能要updateXxx()修改多个字段,insert可能要updateXxx()插入多个字段的值,JVM不知道你的updateXxx()写完了没有,所以要写resultSet.updateRow()|insertRow();   告诉JVM:我对这条记录的改|插入字段已经弄完了,JVM才会同步到数据库中。

    注意是updateRow()、insertRow()、deleteRow(),是Row,不是Rows,同步的只是一条记录。

    所以每操作完一条记录,该手动同步的就要手动同步,不能想着一次性同步所有更新。

     

    CachedRowSet的更新操作:

     1         //从properties文件中加载数据库配置
     2         Properties properties = new Properties();
     3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
     4         properties.load(inputStream);
     5 
     6         String driver = properties.getProperty("driver");
     7         String url = properties.getProperty("url");
     8         String user = properties.getProperty("user");
     9         String pwd=properties.getProperty("password");
    10 
    11         Class.forName(driver);
    12         Connection connection = DriverManager.getConnection(url, user, pwd);
    13 
    14         String sql = "select * from student_tb";
    15         PreparedStatement preparedStatement = connection.prepareStatement(sql);   //CachedRowSet默认就是可更新的,不必传额外的参数
    16         ResultSet resultSet = preparedStatement.executeQuery();
    17         resultSet.next();
    18 
    19         //离线结果集
    20         RowSetFactory rowSetFactory = RowSetProvider.newFactory();
    21         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
    22         cachedRowSet.populate(resultSet);
    23         resultSet.close();
    24         preparedStatement.close();
    25         connection.close();
    26 
    27         while (cachedRowSet.next()){
    28             int id = cachedRowSet.getInt("id");
    29             if (id==15){
    30                 //删除记录
    31                 cachedRowSet.deleteRow();
    32             }
    33             else if(id==20){
    34                 //修改记录
    35                 cachedRowSet.updateString("name","chy1");
    36                 cachedRowSet.updateRow();
    37             }
    38         }
    39 
    40         Connection connection1 = DriverManager.getConnection(url, user, pwd);   //连接已关闭了,需要重新获取一个连接
    41         connection1.setAutoCommit(false);  //将新连接的自动提交设置为false
    42         cachedRowSet.acceptChanges(connection1);  //同步到数据库。

    对CachedRowSet使用deleteRow()、updateRow()不会立刻同步到数据库中,因为连接已经关闭了,同步不了。

    这2个方法相当于把这些同步操作放在一个队列中,当   cachedRowSet.acceptChanges(connection1);   传入一个连接时,就依次执行队列中的同步操作。

    CachedRowSet不能插入一条记录,因为CachedRowSet是批量同步的(队列),插入操作可能会受到队列中其他记录的影响。

    CachedRowSet是默认可更新的,不是默认自动提交的。

    更新操作要求结果集满足2个条件:

    • 结果集只能是单表查询的结果集
    • 结果集中必须含有主键列

    分页

    分页有3种实现方式。

    1、使用sql语句来限定结果集范围

    1 String sql = "select * from student_tb where id>? and id<?";
    2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
    3         preparedStatement.setInt(1,0);
    4         preparedStatement.setInt(2,11);
    5         ResultSet resultSet = preparedStatement.executeQuery();

    这种方式不好,因为区间上的某些记录可能被删除了,id没了。比如1页10条记录,[1,10],但id=5,id=8的记录被删除了(比如注销账户),实际取到的就比10条少。

    1 String sql = "select * from student_tb limit ?,?";
    2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
    3         preparedStatement.setInt(1,0);   //从满足条件的记录中的第1条记录起(参数是下标)
    4         preparedStatement.setInt(2,10);  //只取10条记录
    5         /*
    6         第一个参数可缺省,默认为0,从第一条记录起。
    7         String sql = "select * from student_tb limit 100"; 只取100条记录
    8          */

    能取足10条,但limit是mysql的特性,对应的SQL  Server特性是top、Oracle特性是rownum,不跨数据库。

    2、使用游标来实现

     1  String sql = "select * from student_tb";
     2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
     3         ResultSet resultSet = preparedStatement.executeQuery();
     4 
     5         int start=0;  //开始位置
     6         int pageSize=10;  //每页显示多少条记录
     7         resultSet.absolute(start);  //先转到起始处。参数是下标,0表示第一条记录
     8         while (resultSet.next()){
     9             //......
    10             System.out.println(resultSet.getRow());
    11             if(resultSet.getRow()==start+pageSize)  //getRow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
    12                 break;
    13         }

    3、使用离线查询来实现

     1 //离线结果集
     2         RowSetFactory rowSetFactory = RowSetProvider.newFactory();
     3         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
     4         cachedRowSet.setPageSize(10);  //设置每页显示多少条记录,其实设置的是CachedRowSet的容量
     5         cachedRowSet.populate(resultSet,1);  //设置从结果集中的第几条记录开始填充。cachedRowSet中的记录是结果集中的[1,10]条
     6         resultSet.close();
     7         preparedStatement.close();
     8         connection.close();
     9 
    10         while (cachedRowSet.next()){
    11            //......
    12         }
  • 相关阅读:
    Python3.x和Python2.x的区别
    urllib库python2和python3具体区别
    Oracle实现自增方式:序列+触发器
    菜单
    visual studio 2013连接Oracle 11g并获取数据:(二:实现)
    Oracle连接出现TNS:no listener或者ORA-12514: TNS:listener does not currently know
    visual studio 2013连接Oracle 11g并获取数据:(一:环境搭建)
    C#编程
    Oracle 11g 安装
    Android在Eclipse上的环境配置
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/11371543.html
Copyright © 2011-2022 走看看