这一章详细的介绍了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对象的并发性决定了其内容是否可以更新。
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的可保持性确定使用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对应那行记录并没有真正从数据库文件中抹去,一般是可以再次取到记录的。
码字不易,请点个赞吧!