【问题标题】:JDBC Type Scroll Insensitive and SensitiveJDBC 类型 Scroll Insensitive 和 Sensitive
【发布时间】:2019-06-30 09:20:37
【问题描述】:

在浏览Java JDBC ResultSet Types时,有两种滚动类型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 驱动程序支持 INSENSITIVE ResultSet 对象并且不敏感。是这样吗?如果是,为什么以及哪个驱动程序支持两者?如果没有,那么我哪里出错了。

我查看了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} -> 是的

{TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE} -> 是的

{TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY} -> 是的

【问题讨论】:

  • 您是否验证过它是否真的被创建为敏感信息?如有必要,驱动程序可以降级(并且更可能不支持 TYPE_SCROLL_SENSITIVE 与 CONCUR_UPDATABLE 的组合)。也可以尝试禁用自动提交(默认启用自动提交)。
  • @MarkRotteveel 我用不同的组合进行了验证,例如 (TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY) 但没有运气。还尝试了自动提交错误。你能解释一下'司机可以在必要时降级'是什么意思吗?
  • 我的意思是通过使用ResultSet.getType() 检查实际运行时敏感度来进行验证。如果 JDBC 驱动程序不能满足请求的并发和/或类型,则允许降级并发或类型。
  • 还要确保检查相关的DatabaseMetaData 方法以获得实际提供的灵敏度保证。
  • @MarkRotteveel 我通过 DatabaseMetaData 检查了支持并编辑了我的帖子。您可以检查结果是否为真。任何进一步的建议。

标签: java sql oracle jdbc resultset


【解决方案1】:

对于其他不起作用的功能,您必须在使用它们之前阅读documentation

重要的是窗口的概念

滚动敏感结果集的 Oracle 实现涉及窗口的概念,其窗口大小基于提取大小。窗口大小会影响结果集中行的更新频率。

所以要观察每一行的变化,你必须将fetch size设置为1。

请注意,为 resultSet 设置 fetch size 是不够的,因为默认的 fetch size 为 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 Enterprise Edition Release 12.2.0.1.0 DriverVersion 12.2.0.1.0

【讨论】:

  • 明白。这意味着我们必须将 refreshRow 甚至用于敏感以检测更新的数据,并且由于 jdbc 支持 {insensitive,updatable} 的 refreshRow,因此它清楚地表明如果将 refreshRow 放入程序中它们之间将没有区别。
  • 好吧,要么您按需显式调用 refreshRow(这可能更有意义),要么将 fetch size 设置为 1,然后调用 refreshRow 完成 为你隐含。
  • 没关系。我要查询的是是否按需放置 refreshRow ,然后放置任何 ResultSet 类型的 {insensitive,updatable}{sensitive,updatable} 的行为方式相同。
  • @Nizam 不确定您的配方,但我建议设置光标TYPE_SCROLL_INSENSITIVE 并按需调用refreshRow。您可以完全控制重新读取更新的数据,并且可以使用有意义的 fetch size
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多