`
vvnet
  • 浏览: 116511 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

oracle preparedStatement ResultSet.Type_Scroll_Insensitive 乱码

    博客分类:
  • JAVA
 
阅读更多

问题:

我用的数据库是 oracle 字符集 us7ascii
用preparedStatement(sqlString, ResultSet.Type_Scroll_Insensitive, ResultSet.Concur_read_only)
从数据库中 读取数据后 中文字段乱码,不管是转不转码都是乱码
但是如果preparedStatement(sqlString) 转码成GBK后就能正常显示中,服了。


查询百度,有说是oracle jdbc驱动的问题,这个还没有验证,有时间验证一下,作参考。


深入理解(原文http://www.iteye.com/topic/123557

JDBC2.0后提出了三种不同的cursor类型,用户代码可以在创建Statement指定cursor类型,如下:
Statement createStatement( int resultSetType, int resultSetConcurrency)

cursor类型

ResultSet.TYPE_FORWARD_ONLY

   默认的cursor类型,仅仅支持向前forward,不支持backforward,random,last,first操作,类似单向链表。
   TYPE_FORWARD_ONLY类型通常是效率最高最快的cursor类型

ResultSet.TYPE_SCROLL_INSENSITIVE

   支持backforward,random,last,first操作,对其它数据session对选择数据做出的更改是不敏感,不可见的。

ResultSet.TYPE_SCROLL_SENSITIVE

   支持backforward,random,last,first操作,对其它数据session对选择数据做出的更改是敏感,可见的。

分析

   众所周知,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对应那行记录并没有真正从数 据库文件中抹去,一般是可以再次取到记录的。

总结

    TYPE_FORWARD_ONLY类型通常是效率最高最快的cursor类型,也是最常用的选择。
    TYPE_SCROLL_INSENSITIVE需要在jvm中cache所有fetch到的记录实体,在大量记录集返回时慎用。
    TYPE_SCROLL_SENSITIVE在jvm中cache所有fetch到的记录rowid,需要进行二次查询,效率最低,开销最大

 

 

JDBC ResultSet分析 (原文http://www.iteye.com/topic/560109

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


程序如下:

Java代码  收藏代码
  1. public   static   void  testResultSetSensitive(Connection conn)  throws  Exception{  
  2.   
  3.         String sql = "SELECT c1,c2,c3 FROM test" ;  
  4.         try  {  
  5.             Statement stmt = conn  
  6.                     .createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);  
  7.               
  8.             ResultSet rs = stmt.executeQuery(sql);  
  9.               
  10.             while  (rs.next()) {  
  11.                 System.out.println("[行号:"  + rs.getRow() +  "]\t"  + rs.getString( 1 ) +  "\t"  + rs.getString( 2 )  
  12.                         + "\t"  + rs.getString( 3 ));  
  13.                 Thread.sleep(20000 );  
  14.             }  
  15.               
  16.             rs.close();  
  17.             stmt.close();  
  18.         } catch  (SQLException e) {  
  19.             e.printStackTrace();  
  20.         } finally  {  
  21.             try  {  
  22.                 conn.close();  
  23.             } catch  (Exception e) {  
  24.             }  
  25.         }  
  26.     }  


定义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))

分享到:
评论
2 楼 vvnet 2012-10-11  
时间长了,好像是沿用了“但是如果preparedStatement(sqlString) 转码成GBK后就能正常显示”吧。
1 楼 xdchenggong 2012-10-10  
请问你的乱码问题解决了吗,我也遇到这问题了,找不到解决办法

相关推荐

    采用JDBC进行数据库分页查询

    一次只从数据库中查询最大maxCount条记录 ... PreparedStatement pstat = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); //最大查询到第几条记录.........

    Db.rar_滚动

    对于大结果集,通常使用`ResultSet.TYPE_SCROLL_SENSITIVE`或`ResultSet.TYPE_SCROLL_INSENSITIVE`来创建可滚动的结果集,前者对数据库的修改敏感,后者不敏感。 5. **分页和数据流**:在处理大量数据时,数据滚动...

    JDBCJDBC高级应用

    - 创建可更新结果集时,需要指定并发性类型,如 `ResultSet.CONCUR_UPDATABLE`,并配合 `ResultSet.TYPE_SCROLL_INSENSITIVE` 或 `ResultSet.TYPE_SCROLL_SENSITIVE` 使用。 - 更新结果集中的数据通常涉及 `update...

    javaResultSet常用方法.pdf

    - `ResultSet.TYPE_SCROLL_INSENSITIVE`:可前后滚动,但对数据库的更改不敏感。 - `ResultSet.TYPE_SCROLL_SENSITIVE`:可前后滚动并能感知数据库的更改,但性能较低。 - `resultSetConcurrency`: - `...

    《Java程序设计案例教程》教学课件09Java数据库编程.pptx

    ResultSet.TYPE_SCROLL_INSENSITIVE允许上下移动,但对数据库变化不敏感;ResultSet.TYPE_SCROLL_SENSITIVE则在移动时会反映数据库的最新状态。resultSetConcurrency的ResultSet.CONCUR_READ_ONLY意味着结果集是只读...

    JDBC学习文档

    - **示例**:`Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);` #### 四、PreparedStatement类详解 `...

    JAVA100例之实例55 可滚动结果集

    这里,`ResultSet.TYPE_SCROLL_INSENSITIVE`表示结果集对数据库中的变化不敏感,而`ResultSet.CONCUR_READ_ONLY`表示结果集是只读的。如果需要更新结果集,可以使用`ResultSet.CONCUR_UPDATABLE`。 接下来,执行SQL...

    JDBC连接操作Oracle及Mysql详解

    8. **可滚动的结果集**: ResultSet对象默认是不可滚动的,但通过设置`ResultSet.TYPE_SCROLL_INSENSITIVE`和`ResultSet.CONCUR_READ_ONLY`,可以创建一个可滚动的结果集,允许前后移动和检查是否已到达结果集的末尾...

    2022年Java数据库编程中的技巧Java教程.docx

    创建此类记录集时,需要在创建`Statement`时指定`ResultSet.TYPE_SCROLL_SENSITIVE`或`ResultSet.TYPE_SCROLL_INSENSITIVE`,并设置并发模式(如`ResultSet.CONCUR_READ_ONLY`)。 - 对于`PreparedStatement`,同样...

    JDBC2.0新功能

    但在JDBC 2.0中,通过`ResultSet.TYPE_SCROLL_SENSITIVE`和`ResultSet.TYPE_SCROLL_INSENSITIVE`选项,开发者可以创建可滚动的结果集。这使得开发人员可以在结果集中前后移动,甚至直接跳转到特定行。例如,使用`...

    jdbc示例代码

    然而,通过设置Statement的类型为ResultSet.TYPE_SCROLL_INSENSITIVE或ResultSet.TYPE_SCROLL_SENSITIVE,我们可以获取一个支持滚动的游标。滚动游标允许我们前后移动结果集,不仅可以向上或向下遍历,还可以定位到...

    适用于jdk1.8与Oracle数据库连接的OJDBC的驱动jar包

    - **游标**:Oracle的游标允许向前和向后滚动的结果集,通过设置`ResultSet.TYPE_SCROLL_INSENSITIVE`和`ResultSet.CONCUR_READ_ONLY`属性。 - **连接池**:使用连接池如C3P0或Apache DBCP,可以有效地管理数据库...

    关于java数据库基本操作

    PreparedStatement ps = cn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ``` 2. **批量更新** - 使用`addBatch()`方法添加多个更新语句到批处理中,然后调用`...

    关于JAVA数据库基本操作

    PreparedStatement ps = cn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ``` 3. **使用`ResultSet`的方法实现记录集的滚动**: ```java rs.absolute(9000); // ...

    JSP与SQL Server连接.pdf

    - **随机访问**:若需实现随机访问,可以创建支持滚动的`Statement`对象,如`stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)`。 5. 指针移动 - `ResultSet`的指针...

    操作mysql数据库的类.pdf

    在Java中,有多种游标类型,如`ResultSet.TYPE_FORWARD_ONLY`(只向前)、`ResultSet.TYPE_SCROLL_INSENSITIVE`(不可感知数据改变的滚动)和`ResultSet.TYPE_SCROLL_SENSITIVE`(可感知数据改变的滚动)。...

    JDBC使用游标实现分页查询的方法

    然后创建一个PreparedStatement对象,设置游标类型为`ResultSet.TYPE_SCROLL_INSENSITIVE`,并发控制为`ResultSet.CONCUR_READ_ONLY`,以确保结果集的只读性。 - 使用`setMaxRows(startNo+maxCount-1)`限制返回的...

    jdbc相关ppt

    `ResultSet.TYPE_SCROLL_INSENSITIVE`可以在任何位置滚动,但不关心数据变化;`ResultSet.TYPE_SCROLL_SENSITIVE`是敏感模式,可以感知数据的变化。 4. **批量更新**:通过`addBatch()`方法将多条SQL语句添加到...

    Java数据库编程中的几个常用技巧

    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY ); ``` 3. **使用可滚动结果集** - 可以使用`ResultSet`的`absolute`方法来移动游标: ```java ResultSet rs = ...; // 获取结果集 rs....

Global site tag (gtag.js) - Google Analytics