`

【原创】JDBC ResultSet分析

阅读更多

 

JDBC1.0 JDBC2.0JDBC3.0 中分别用以下方法创建Statement

JDBC1.0 createStatement()

JDBC2.0 createStatement(resultSetType, resultSetConcurrency)

JDBC3.0 : createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)

 

下面依次分析resultSetTyperesultSetConcurrencyresultSetHoldability 这几个参数的含义。

 

一 ResultSetType

 

      resultSetType 的可选值有: ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_SENSITIVE

 

1 ResultSet.TYPE_FORWARD_ONLY

默认的cursor 类型,仅仅支持结果集forward ,不支持backforwardrandomlastfirst 等操作。  

 

2 ResultSet.TYPE_SCROLL_INSENSITIVE

支持结果集backforwardrandomlastfirst 等操作,对其它session 对数据库中数据做出的更改是不敏感的。

实现方法:从数据库取出数据后,会把全部数据缓存到cache 中,对结果集的后续操作,是操作的cache 中的数据,数据库中记录发生变化后,不影响cache 中的数据,所以ResultSet 对结果集中的数据是INSENSITIVE 的。

 

3 ResultSet.TYPE_SCROLL_SENSITIVE

支持结果集backforwardrandomlastfirst 等操作,对其它session 对数据库中数据做出的更改是敏感的,即其他session 修改了数据库中的数据,会反应到本结果集中。

 

实现方法:从数据库取出数据后,不是把全部数据缓存到cache 中,而是把每条数据的rowid 缓存到cache 中,对结果集后续操作时,是根据rowid 再去数据库中取数据。所以数据库中记录发生变化后,通过ResultSet 取出的记录是最新的,即ResultSetSENSITIVE 的。insertdelete 操作不会影响到ResultSet ,因为insert 数据的rowid 不在ResultSet 取出的rowid 中,所以insert 的数据对ResultSet 是不可见的,而delete 数据的rowid 依旧在ResultSet 中,所以ResultSet 仍可以取出被删除的记录( 因为一般数据库的删除是标记删除,不是真正在数据库文件中删除 )。

 

做个试验,验证一下SENSITIVE 特性。数据库为oracle10g ,驱动为ojdbc14.jar

test 表中数据如下:

 

 

c1 c2 c3
1c1 1c2 1c3
2c1 2c2 2c3
3c1 3c2 3c3

 

程序如下:

public static void testResultSetSensitive(Connection conn) throws Exception{

		String sql = "SELECT c1,c2,c3 FROM test";
		try {
			Statement stmt = conn
					.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
			
			ResultSet rs = stmt.executeQuery(sql);
			
			while (rs.next()) {
				System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2)
						+ "\t" + rs.getString(3));
				Thread.sleep(20000);
			}
			
			rs.close();
			stmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (Exception e) {
			}
		}
	}

 

定义ResultSet ResultSet. TYPE_SCROLL_SENSITIVE 类型,首先执行 sql 访问数据库,然后执行 rs.next() 移动游标取数据。在循环里面加上 Thread.sleep (20000) 的目的是为了我们有时间在后台把数据库里的数据改了。比如当在循环里打印出第一行的数据后,我们在后台,把第三行数据的 c3 列改成 ”3uuu” 。如果 ResultSet 真的是敏感的话,那应该取出 ”3uuu” ,而不是原始的“ 3c 3 ”。但最终的结果却是如下:

 

[ 行号: 1] 1c1   1c2   1c3

[ 行号: 2] 2c1   2c2   2c3

[ 行号: 3] 3c1   3c2   3c3

 

数据没变呀,ResultSet 不敏感啊!于是去查阅资料,找了n 久,还是在英文文档上找到了答案。原来是fetchsize 的问题。调用ResultSetnext 方法取数据时,并不是每调用一次方法就去数据库里查一次,而是有个fetchSize, 一次取fetchSize 条数据。Oracle 默认的fetchsize 等于10 ,所以上面的代码在第一次调用rs.next() 时,就已经把3 条数据都取出来了,所以才会有上面的结果。

 

      第二次实验,在ResultSet rs = stmt.executeQuery(sql); 前面加上 stmt.setFetchSize(1); fetchSize 设置为1 。然后重新第一次实验的步骤,发现最 终结果为:

[ 行号: 1] 1c1   1c2   1c3

[ 行号: 2] 2c1   2c2   2c3

[ 行号: 3] 3c1   3c2   3uuu

    原因就是 fetchsize 设置为 1 时,每次 next 取数时都会重新用 rowid 取数据库里取数据,当然取到的是最新的数据了。

  

      二 ResultSetConcurrency

 

      ResultSetConcurrency的可选值有2个:
      ResultSet.CONCUR_READ_ONLY 在ResultSet中的数据记录是只读的,不可以修改
      ResultSet.CONCUR_UPDATABLE 在ResultSet中的数据记录可以任意修改,然后更新到数据库,可以插入,删除,修改。

 

      三 ResultSetHoldability

   ResultSetHoldability 的可选值有2

     HOLD_CURSORS_OVER_COMMIT: 在事务commitrollback 后,ResultSet 仍然可用。
     CLOSE_CURSORS_AT_COMMIT:
在事务commitrollback 后,ResultSet 被关闭。

  

     需要注意的地方:

   1 Oracle 只支持HOLD_CURSORS_OVER_COMMIT

   2 :当Statement 执行下一个查询,生成第二个ResultSet 时,第一个ResultSet 会被关闭,这和是否支持支持HOLD_CURSORS_OVER_COMMIT 无关。

 

     四 验证数据库是否支持ResultSet的各种特性

 

不同的数据库版本及 JDBC 驱动版本,对 ResultSet 的各种高级特性的支持是不一样的,我们可以通过以下方法,来验证具体的数据库及 JDBC 驱动,是否支持 ResultSet 的各种特性。

    

     DatabaseMetaData dbMeta = conn.getMetaData();

      然后调用 DatabaseMetaData 对象的以下方法:

       boolean supportsResultSetType(int resultSetType);

       boolean supportsResultSetConcurrency(int type, int concurrency);

       boolean supportsResultSetHoldability(int holdability);

 

    参考的2 篇英文文档:

 http://cs.felk.cvut.cz/10gr2/java.102/b14355/jdbcvers.htm JDBC Standards Support

 http://download.oracle.com/docs/cd/B10501_01/java.920/a96654/resltset.htm#1023642 (Oracle9i JDBC Developer's Guide and Reference Release 2 (9.2))

 

分享到:
评论
11 楼 zhenkm0507 2010-01-06  
fuwang 写道
zhenkm0507 写道

resultSetType是FORWARD_ONLY时,是不缓存数据的。

是指oracle不缓存数据吗?
zhenkm0507 写道

经测试,ResultSet.TYPE_SCROLL_INSENSITIVE 、ResultSet.TYPE_SCROLL_SENSITIVE下,查询大批量数据会导致溢出,而FORWARD_ONLY不会。

这里的溢出是指什么,是oracle还是客户端的JVM?


我是在oracle下做的测试,是客户端的JVM溢出。
10 楼 fuwang 2010-01-05  
zhenkm0507 写道

resultSetType是FORWARD_ONLY时,是不缓存数据的。

是指oracle不缓存数据吗?
zhenkm0507 写道

经测试,ResultSet.TYPE_SCROLL_INSENSITIVE 、ResultSet.TYPE_SCROLL_SENSITIVE下,查询大批量数据会导致溢出,而FORWARD_ONLY不会。

这里的溢出是指什么,是oracle还是客户端的JVM?
9 楼 zhenkm0507 2010-01-05  
fuwang 写道
感谢楼主的试验。
我下两个结论,不知道对不对。
1)进行查询时,oracle会根据查询的sql把符合条件的数据进行缓存。至于INSENSITIVE还是SENSITIVE,这是要告诉数据库如何作缓存,INSENSITIVE是把全部数据缓存到cache,SENSITIVE是把每条记录的rowid缓存到cache中。
2)resultSetType是SCROLL还是默认的FORWARD_ONLY,都是jdbc自己的行为,不会影响oracle内部的处理过程。


resultSetType是FORWARD_ONLY时,是不缓存数据的。经测试,ResultSet.TYPE_SCROLL_INSENSITIVE 、ResultSet.TYPE_SCROLL_SENSITIVE下,查询大批量数据会导致溢出,而FORWARD_ONLY不会。
8 楼 zhenkm0507 2010-01-04  
关于resultSetType, resultSetConcurrency, resultSetHoldability 这3个参数的实际使用,欢迎大家群策群力,积极回帖,共同提高嘛!
7 楼 zhenkm0507 2010-01-04  
mercyblitz 写道
楼主的3 :ResultSet.TYPE_SCROLL_SENSITIVE例子并不能很好地证明结论。

原因如下:
1.例子环境并不是并发,你使用Sleep方法不能产生同步效应
2.例子中,数据的一致性那是事务的范畴。
3.例子中,你一条条地取即使是INSENSITIVE,都可能会是同步数据。
4.JDBC规范中,并没有规定非分布式Connection的实现机制,也就说Connection是使用的“拉”还是“推”的模式来同步数据,无论是“拉”还是“推”,使用Sleep都是不合适的。


mercyblitz,你好!你表达的意思,我不是很明白。我用sleep的原因是让程序生成ResultSet后,暂停取数,然后启动另一会话或事务去改掉数据库中的数据,然后检查原程序生成的ResultSet中取出的数据是否是新的。这和你说的“同步”好像没关系吧?
6 楼 mercyblitz 2010-01-04  
楼主的3 :ResultSet.TYPE_SCROLL_SENSITIVE例子并不能很好地证明结论。

原因如下:
1.例子环境并不是并发,你使用Sleep方法不能产生同步效应
2.例子中,数据的一致性那是事务的范畴。
3.例子中,你一条条地取即使是INSENSITIVE,都可能会是同步数据。
4.JDBC规范中,并没有规定非分布式Connection的实现机制,也就说Connection是使用的“拉”还是“推”的模式来同步数据,无论是“拉”还是“推”,使用Sleep都是不合适的。
5 楼 fuwang 2010-01-04  
感谢楼主的试验。
我下两个结论,不知道对不对。
1)进行查询时,oracle会根据查询的sql把符合条件的数据进行缓存。至于INSENSITIVE还是SENSITIVE,这是要告诉数据库如何作缓存,INSENSITIVE是把全部数据缓存到cache,SENSITIVE是把每条记录的rowid缓存到cache中。
2)resultSetType是SCROLL还是默认的FORWARD_ONLY,都是jdbc自己的行为,不会影响oracle内部的处理过程。
4 楼 zhangxiaoming 2009-12-31  
顶!

我个人感觉,最难掌握的是什么时候使用这些特性。

能否给出几个真实的使用场景。
3 楼 siukeung 2009-12-31  
同意楼上。

不过也学习咯。
2 楼 lt0604 2009-12-31  
JDBC的实现根据厂商的不同而不同,以此概彼。如MS sql2000和2005驱动就很不同,还不能同时用
1 楼 kimmking 2009-12-31  
实际的各种jdbc实现,并非按照标准来的,特别是一些边边角角的参数配置等。

以前看derby10.x的代码,看到很多选项里写着,暂不支持之类的东西。

相关推荐

    如何从 Java 存储过程将 JDBC ResultSet 作为 Ref Cursor 返回.doc

    JDBC提供了一种标准的方式来访问各种数据库,包括SQL查询的执行、结果集(ResultSet)的处理等。ResultSet是JDBC中用于存储查询结果的一个接口,它表示从数据库中检索的数据集。而REF CURSOR则是PL/SQL(Oracle...

    ResultSet转化为json,json转化为List

    使用Java的JDBC API,遍历ResultSet并创建User对象的列表: ```java List<User> userList = new ArrayList(); while (resultSet.next()) { User user = new User(); user.setName(resultSet.getString("name")...

    JDBC编程resultset游标控制

    JDBC通信原理 JDBC驱动类型 JDBC构成 JDBC程序5步走 滚动的结果集 可更新的结果集 SQL数据类型对应的Java类型 事务及批量处理 行集、连接池、LDAP

    Java-JDBC【之】数据类型、封装JDBCUtil、封装通用增删改、ResultSet与ResultSetMetaData

    Java-JDBC【之】数据类型、封装JDBCUtil、封装通用增删改、ResultSet与ResultSetMetaData、查询结果集映射Map与ListMap 1.数据类型 2.封装通用增删改 2.1.封装JDBCUtil 2.2.封装Dao通用增删改 2.3.测试 3.ResultSet...

    JDBC基础教程之ResultSet对象.doc )

    ### JDBC基础教程之ResultSet对象详解 #### 一、ResultSet对象概览 `ResultSet`对象是Java Database Connectivity (JDBC) API中的一个核心组件,用于处理SQL查询结果。它充当了一个临时的数据存储,其中包含了所有...

    jdbcObjectMapper:JDBC ResultSet对象映射器

    假设我们的ResultSet代表这样的列。 这些列是从表的某些联接(付款,用户,公司)中选择的,并且这些列在一个查询结果中:id,payment_date,payment_amount,user_id,user_name,user_surname,company_id,...

    ResultSet

    ResultSet是Java数据库连接(JDBC)中的核心接口,它用于存储和检索数据库查询结果。当你执行SQL查询并从数据库获取数据时,结果会被封装在ResultSet对象中。在本篇文章中,我们将深入探讨ResultSet的主要概念、操作...

    4. 尚硅谷_佟刚_JDBC_通过 ResultSet 执行查询操作.wmv

    JavaJDBC的视频,通过ResultSet执行查询操作,视频详细描述了如何使用ResultSet执行查询的案例。

    JAVA 版本ResultSet 转换为JAVABEAN的工具类

    在Java编程中,ResultSet是处理数据库查询结果的主要接口,它由Statement或PreparedStatement对象执行SQL查询后返回。而JavaBean是一种符合特定规范的Java类,通常用于封装数据,便于数据的传输和操作。当我们从...

    java组件开发(15) JDBC操作工具类与ResultSet数据

    java组件开发(15) JDBC操作工具类与ResultSet数据

    java种菜源码-SQLDataSet:这个项目是一个简单的工具,用于从JDBCResultSet中unSerializeJavaBean

    JDBC ResultSet 中取消序列化 Java Bean。 对于 Android SQLite 也见 1. 注释 public class Fruit { @DsColumn ( " Name " ) public String name; // the column in database is "Name" @DsIgnore public String ...

    ResultSet 转为listmap

    在 Java 中,使用 JDBC 连接数据库时,通常会返回一个 ResultSet 对象,该对象包含了查询结果集的所有记录。为了方便数据处理和使用,我们需要将 ResultSet 转为 List,以便于后续的数据处理和展示。 下面是将 ...

    JDBC代码JDBC代码JDBC代码

    首先,JDBC的核心组件包括驱动程序、数据库连接(Connection)、数据库查询(Statement/PreparedStatement)、结果集(ResultSet)以及事务管理。在Java应用程序中,我们通常通过以下五个基本步骤来使用JDBC: 1. *...

    JdbcSql.rar_java resultset_jtable

    使用JDBC时,我们需要导入`java.sql.*`包下的相关类,如`DriverManager`、`Connection`、`Statement`和`ResultSet`。 2. **ResultSet**: `ResultSet`是执行SQL查询后返回的结果集,它是一个接口,用于存储查询结果...

    实用的jdbc的工具类,提供多种ResultSet的转化方法

    次类对ResultSet进行封装,可以将其转化为List,Map,BO等

    jdbc jdbc jdbc

    Java Database Connectivity(JDBC)是Java编程语言中用于与各种数据库进行交互的一种标准接口。它由Sun Microsystems(现为Oracle公司)开发并定义,作为Java平台的一部分,允许Java应用程序通过编写Java代码来访问...

    基于java的jdbc的效率分析

    理解JDBC的效率分析至关重要,因为它直接影响到应用程序的性能和资源利用率。 首先,我们要明白JDBC的基本工作流程。它包括以下步骤: 1. 加载驱动:程序通过`Class.forName()`方法加载对应的数据库驱动。 2. 获取...

    java数据库连接ResultSet

    Java 数据库连接 ResultSet Java 数据库连接中的 ResultSet 是一个非常重要的概念,它包含符合 SQL 语句中条件的所有行,并且提供了对这些行中数据的访问。ResultSet 通过一套 get 方法访问当前行中的不同列,例如 ...

    小白看得懂的MySQL JDBC 反序列化漏洞分析 - 先知社区1

    【MySQL JDBC 反序列化漏洞分析】 MySQL JDBC 反序列化漏洞主要涉及到Java数据库连接(JDBC)驱动程序中的安全问题。JDBC是Java中用于与数据库交互的标准接口,允许开发者使用Java语言执行SQL语句。在特定版本的...

    jdbc核心代码.docx

    JDBC核心代码详解 在本文中,我们将详细解释JDBC(Java Database Connectivity)的核心代码,涵盖了JDBC的基本概念、步骤、语句和实践操作。 JDBC概述 JDBC是Java语言中用于连接数据库的API(Application ...

Global site tag (gtag.js) - Google Analytics