java - JDBC类型滚动不敏感和敏感

标签 java sql oracle jdbc resultset

在查看Java JDBC ResultSet类型时,有两种滚动类型TYPE_SCROLL_SENSITIVE和TYPE_SCROLL_INSENSITIVE,这是我所理解的。但是当我去实际执行的时候,并没有看到效果。下面是代码:

package com.jdbc.resultsettypeandconcurrency;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TypeInSensitiveConcurUpdate {

    public static void main(String[] args) {
        Connection con = null;
        Statement stmt = null;

        try {
            System.out.println("loading the driver.....");
            Class.forName("oracle.jdbc.driver.OracleDriver");
            System.out.println("Driver loaded");
            con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "user", "pass");
            if(con!=null) {
                System.out.println("Connected to database");

            } else {
                System.out.println("Could not Get Connection");
            }

            stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
            ResultSet rs = stmt.executeQuery(query);
            System.out.println();
            int cnt = 1;
            while(rs.next()) {
                System.out.print(rs.getString("COF_NAME")+", ");
                System.out.print(rs.getInt("SUP_ID")+", ");
                System.out.print(rs.getFloat("PRICE")+", ");
                System.out.print(rs.getInt("SALES")+", ");
                System.out.print(rs.getInt("TOTAL")+"\n");
                if(cnt == 2){
                    try {
                        Thread.sleep(20 * 1000);/**LINE:39*/
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                cnt++;
            }
            System.out.println();

        } catch(ClassNotFoundException e) {
            System.out.println("ClassNotFoundException : Driver Class not found");
            System.out.println(e.getMessage());

        } catch(SQLException e) {
            System.out.println("SQL Error "+e.getMessage());
            System.out.println(e.getErrorCode());

        } finally {
            if(stmt!=null) {
               stmt.close();
            }
            if(con!=null) {
               con.close();
            }
            System.out.println("All Connection closed");
        }
    }
}

当程序到达第 39 行时,我从后端更新数据库中的记录。对于 TYPE_SCROLL_INSENSITIVE,它不会显示应执行的更新记录,但对于 TYPE_SCROLL_SENSITIVE,它不会执行所需的行为。它必须显示更新的记录,但不显示。谁能告诉我为什么会这样吗?

我在谷歌搜索(不是Java文档或JLS)时在某处读到ODBC瘦驱动程序,OCI驱动程序支持不敏感的结果集对象并且不敏感。是这样吗?如果是,为什么以及哪个驱动程序支持两者?如果不是,那么我哪里出错了。

我浏览了link ,但没有指出我的问题。任何建议将不胜感激。

编辑:添加这些行来检查支持

DatabaseMetaData meta = con.getMetaData();
System.out.println("{TYPE_SCROLL_INSENSITIVE, CONCUR_UPDATABLE} -> "+
                meta.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE));
System.out.println("{TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE} -> "+
                    meta.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE));
System.out.println("{TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY} -> "+
                    meta.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY));

下面是我得到的结果:

{TYPE_SCROLL_INSENSITIVE,CONCUR_UPDATABLE} -> true

{TYPE_SCROLL_SENSITIVE,CONCUR_UPDATABLE} -> true

{TYPE_SCROLL_SENSITIVE,CONCUR_READ_ONLY} -> true

最佳答案

与其他不起作用的功能一样,您必须阅读documentation在使用它们之前。

重要的是窗口的概念

The Oracle implementation of scroll-sensitive result sets involves the concept of a window, with a window size that is based on the fetch size. The window size affects how often rows are updated in the result set.

因此,要观察每一行的变化,必须将获取大小设置为1。

请注意,仅设置 resultSet 的获取大小是不够的,因为默认获取大小为 10,并且更改仅对第 11 行及后续行有效。

因此必须在 prepareStatement 上设置获取大小:

 def stmt = con.prepareStatement("""select id, val from test
 where  id between ? and ?  order by id""", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)
 stmt.setFetchSize(1)
 // set bind variables and execute statement
 

现在,每次调用 rs.next() 都会打开一个新窗口,这会导致内部调用 refreshRow

从数据库获取当前值。

请注意,此行为仅针对 TYPE_SCROLL_SENSITIVE 执行,对于 TYPE_SCROLL_INSENSITIVE 不会调用 refreshRow,因此您会看到常量数据 从最初的查询开始,即使您切换了窗口。您可以显式调用 refreshRow 来查看相同的效果。

从技术上讲,该功能是使用两个光标来实现的。第一个对应于使用的查询,仅添加 ROWID 列。

 select rowid as "__Oracle_JDBC_internal_ROWID__", id, val from test
 where  id between :1  and :2   order by id
 

在每个窗口切换时调用第二个游标(即,对于获取的每行,获取大小 = 1),简单外部将保存的 rowid 与第一个游标的查询进行连接,以重新获取当前数据。

WITH "__JDBC_ROWIDS__" AS (SELECT COLUMN_VALUE ID, ROWNUM NUM FROM TABLE(:1 ))
SELECT "__JDBC_ORIGINAL__".*
FROM (select rowid as "__Oracle_JDBC_internal_ROWID__", id, val from test
where  id between :2  and :3   order by id) "__JDBC_ORIGINAL__", "__JDBC_ROWIDS__"
WHERE "__JDBC_ORIGINAL__"."__Oracle_JDBC_internal_ROWID__"(+) = "__JDBC_ROWIDS__".ID
ORDER BY "__JDBC_ROWIDS__".NUM 

    

那里有类似的问题,但没有一个真正解释了问题,所以我不会将此问题标记为重复:

Behaviour of ResultSet.TYPE_SCROLL_SENSITIVE

JDBC ResultSet Type_Scroll_Sensitive

JDBC result set type scroll sensitive

简单的回答是,您使用的默认提取大小太高,无法观察单行的更新

测试完成于 Oracle Database 12c 企业版版本 12.2.0.1.0 驱动程序版本12.2.0.1.0

关于java - JDBC类型滚动不敏感和敏感,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54553339/

相关文章:

database - 如何检查Oracle实例是使用pfile还是spfile启动的?

java - 双整数转换困惑

java - 将 EditText 获取为 String,然后显示在 Toast 中

mysql - HQL 和带有联接的子查询

sql - 删除自连接中的重复关系

mysql - 具有多个条件OR/AND的SQL连接不起作用

oracle - 如何使用 VARRAY 参数调试存储过程?

java - 有没有办法通过swagger注释为不同端点资源使用的模型类编写不同的文档?

java - 如何将 JSP 页面添加到使用 Jetty 的 Java 应用程序

oracle - : SQL Error: ORA-00604: error occurred at recursive SQL level 1如何解决