ResultSet详解

序言

这一章详细的介绍了ResultSet,可以帮助我们更好的了解它。并且在使用中给到我们一些更优解。

ResultSet类型

ResultSet对象的类型主要体现在两个方面:
(1)游标可操作的方式。
(2)ResultSet对象的修改对数据库的影响。

ResultSet有3种不同的类型,分别说明如下:
(1)ResultSet.TYPE_FORWORD_ONLY
结果集的游标只能向下滚动。
(2)ResultSet. TYPE_SCROLL_INSENSITIVE
对结果不敏感,ResultSet决定不了数据的改变。
(3)ResultSet.TYPE_SCROLL_SENSITIVE
返回可滚动的结果集,当数据库变化时,当前结果集同步改变

** 默认的类型是TYPE_FORWORD_ONLY**

ResultSet并发性

ResultSet对象的并发性决定了其内容是否可以更新。
Connection接口提供了createStatement()方法的3个变体,其中方法的签名之一如下:

Statement createStatement(int resultSetType, int resultSetConcurrency)

此方法接受两个整数类型变量,其中一个代表ResultSet的类型,另一个代表ResultSet的并发性。

该ResultSet的接口提供了两个值,指定ResultSet的并发性。

1、CONCUR_READ_ONLY:如果在创建ResultSet对象时将此值设置为并发值,则无法更新ResultSet的内容,您只能读取/检索它们。
2、CONCUR_UPDATABLE:如果在创建ResultSet对象时将此值设置为并发值,则可以更新ResultSet的内容。

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
Or,
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.
ResultSet.CONCUR_UPDATABLE);

ResultSet可保持性

ResultSet的可保持性确定使用commit()Connection接口的方法提交事务(包含 游标/ ResultSet对象)时是关闭还是保持ResultSet对象(光标)打开。

您可以使用setHoldability()Connection接口的方法设置ResultSet可保持性。

con.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);

ResultSet接口提供两个值来指定ResultSet的可保持性,即CLOSE_CURSORS_AT_COMMIT:当调用Connection对象的commit()方法时,不关闭当前事务创建的ResultSet对象。
HOLD_CURSORS_OVER_COMMIT:当调用Connection对象的commit()方法时,关闭当前事务创建的ResultSet对象。正确的使用可以提高程序的性能。

让我们使用CREATE语句在MySQL数据库中创建一个名为MyPlayers的表,如下所示-

CREATE TABLE MyPlayers(
   ID INT,
   First_Name VARCHAR(255),
   Last_Name VARCHAR(255),
   Date_Of_Birth date,
   Place_Of_Birth VARCHAR(255),
   Country VARCHAR(255),
   PRIMARY KEY (ID)
);
insert into MyPlayers values(1, 'Shikhar', 'Dhawan', DATE('1981-12-05'), 'Delhi', 'India');
insert into MyPlayers values(2, 'Jonathan', 'Trott', DATE('1981-04-22'), 'CapeTown', 'SouthAfrica');
insert into MyPlayers values(3, 'Kumara', 'Sangakkara', DATE('1977-10-27'), 'Matale', 'Srilanka');
insert into MyPlayers values(4, 'Virat', 'Kohli', DATE('1988-11-05'), 'Delhi', 'India');
insert into MyPlayers values(5, 'Rohit', 'Sharma', DATE('1987-04-30'), 'Nagpur', 'India');
insert into MyPlayers values(6, 'Ravindra', 'Jadeja', DATE('1988-12-06'), 'Nagpur', 'India');
insert into MyPlayers values(7, 'James', 'Anderson', DATE('1982-06-30'), 'Burnley', 'England');
public static void main(String args[]) throws SQLException {
      //注册驱动程序
      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
      //获得连接
      String url = "jdbc:mysql://localhost/mydatabase";
      Connection con = DriverManager.getConnection(url, "root", "password");
      System.out.println("Connection established......");
      //将自动提交设置为false-
      con.setAutoCommit(false);
      //将可保存性设置为CLOSE_CURSORS_AT_COMMIT-
      con.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
      //创建一个Statement对象
      Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
      //检索数据
      ResultSet rs = stmt.executeQuery("select * from MyPlayers");
      System.out.println("Contents of the table");
      while(rs.next()) {
         System.out.print("ID: "+rs.getString("ID")+", ");
         System.out.print("First_Name: "+rs.getString("First_Name")+", ");
         System.out.print("Last_Name: "+rs.getString("Last_Name"));
         System.out.print("Date_Of_Birth: "+rs.getString("Date_Of_Birth")+", ");
         System.out.print("Place_Of_Birth: "+rs.getString("Place_Of_Birth"));
         System.out.print("Country: "+rs.getString("Country"));
         System.out.println("");
      }
      //插入新行
      rs.moveToInsertRow();
      rs.updateInt(1, 8);
      rs.updateString(2, "Ishant");
      rs.updateString(3, "Sharma");
      rs.updateDate(4, new Date(904694400000L));
      rs.updateString(5, "Delhi");
      rs.updateString(6, "India");
      rs.insertRow();
      //提交事务
      con.commit();
      boolean bool = rs.isClosed();
      if(bool) {
         System.out.println("ResultSet object is closed");
      } else {
         System.out.println("ResultSet object is open");
      }
   }

如果设置为CLOSE_CURSORS_AT_COMMIT,最后输出为

ResultSet object is closed

反之:

System.out.println("ResultSet object is open");

游标

众所周知,JDBC对数据库进行数据查询时,数据库会创建查询结果的cache和cursor。而数据库的cursor是不支持backforward,random,last,first操作,仅仅只支持向前forward。那么TYPE_SCROLL_INSENSITIVE是如何实现支持backforward,random,last,first的呢?很简单,TYPE_SCROLL_INSENSITIVE的Statement查询把所有fetch的记录都缓存到JVM的Resultset对象内,如果有10个记录,直接跳到最后记录,TYPE_SCROLL_INSENSITIVE方式下把fetch所有记录到jvm端,并缓存下来,再进行random就是在数据库数组里面进行的。这也是TYPE_FORWARD_ONLY类型通常是效率最高最快的cursor类型原因,如果要做一些复杂的功能,必然是要牺牲一些效率的。

那么为什么TYPE_SCROLL_INSENSITIVE对选择数据做出的更改是不敏感,不可见的呢?前面提到,JDBC对数据库进行数据查询时,数据库会创建查询结果的cache和cursor,如下面sql:
select name,id from foo
用jdbc执行上面的sql语句时,数据库会把foo表所有记录的name和id字段缓存到cache中,之后cache和真正的数据库数据文件没有任何联系了,foo表发生的改变在查询完成后不会自动同步到cache上去,因此TYPE_SCROLL_INSENSITIVE对选择数据做出的更改是不敏感,不可见。
那么TYPE_SCROLL_SENSITIVE是怎么做到其它数据session对选择数据做出的更改是敏感,可见的。上面的sql语句用TYPE_SCROLL_SENSITIVE的Statement来执行,会转化成以下的sql语句:
select rowid from foo
数据库这时候是把foo表所有记录的rowid缓存到cache中,用户代码在fetch记录时,再继续做以下查询:
select name,id from foo where rowid=?
因此这时候发生的查询是实时从真正的数据库数据文件中取,因此对期间发生的数据更改是可见的,敏感的。但是这种可见性仅限于update操作,而insert和delete同样是不可见的。因为如果查询发生在insert之前,insert生成的rowid并不会反应在cache中的rowid结果集上。在一个记录的rowid已经缓存到cache中,这时候被删除了,但一般数据库的删除是标记删除,也就是说rowid对应那行记录并没有真正从数据库文件中抹去,一般是可以再次取到记录的。

结束语

码字不易,请点个赞吧!

你可能感兴趣的:(Mybatis深入解析源码,java,算法,数据库)