ResultSet.TYPE_SCROLL_SENSITIVE 的行为

发布于 2024-08-18 16:56:25 字数 956 浏览 1 评论 0原文

我对 TYPE_SCROLL_SENSITIVE 类型的 ResultSet 的行为感到困惑。

我对此的理解是:

  1. 我执行一个选择查询,该查询返回一个结果集。我打印出第一行中特定列的值。
  2. 然后,我执行 Thread.sleep(10000),这会使程序暂停 10 秒。
  3. 当程序处于睡眠状态时,我手动对数据库中的同一列进行更新(通过 SQL 提示符)。
  4. 10 秒后,我再次打印结果集第一行中同一列的值。

在步骤 4 中,我希望打印的列值与步骤 1 中打印的值不同。但我总是得到相同的值(即使我的 ResultSet 类型为 SCROLL_TYPE_SENSITIVE)。

我在这里误解了什么吗?

下面是我使用的代码。

private void doStuff() throws Exception
{
    final String query = "select * from suppliers where sup_id=420";

    Statement stmt = this.con.createStatement(
        ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

    ResultSet rs = stmt.executeQuery(query);

    rs.next();

    System.out.println("City : " + rs.getString("city"));

    Thread.sleep(10000); // While this executes, I do a manual update !

    System.out.println("City : " + rs.getString("city"));
}

I am confused about the behaviour of a ResultSet that is of type TYPE_SCROLL_SENSITIVE.

My understanding of this is:

  1. I execute a select query that returns me a result set. I print out the value of a particular column in the first row.
  2. I then execute Thread.sleep(10000), which halts the program for 10 seconds.
  3. While the program is sleeping, I manually do an update to the same column in the DB (through the SQL prompt).
  4. After 10 seconds, I again print the value of the same column in the first row of the result set.

In step 4, I expect the printed column value to be different from the value printed in step 1. But I always get the same value (even if my ResultSet is of type SCROLL_TYPE_SENSITIVE).

Am I misunderstanding something here ?

Below is the code I use.

private void doStuff() throws Exception
{
    final String query = "select * from suppliers where sup_id=420";

    Statement stmt = this.con.createStatement(
        ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

    ResultSet rs = stmt.executeQuery(query);

    rs.next();

    System.out.println("City : " + rs.getString("city"));

    Thread.sleep(10000); // While this executes, I do a manual update !

    System.out.println("City : " + rs.getString("city"));
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

口干舌燥 2024-08-25 16:56:25

我是否误解了什么?

是的。您必须再次获取表的最新状态,方法是自行启动 SELECT 或调用 ResultSet.refreshRow()。此外,请阅读 ResultSet.refreshRow() 之前使用它,否则你可能会得到意想不到的结果。

该文档声明有关 TYPE_SCROLL_SENSITIVE,

TYPE_SCROLL_SENSITIVE

指示 a 类型的常量
可滚动的 ResultSet 对象
并且通常对变化敏感
别人做的。

这仅仅意味着它会对同一 ResultSet 对象中其他人所做的更改敏感。要理解这个概念,我建议查看官方 JDBC 教程:更新表

好的,编辑我的帖子以包含原始教程中的特定行,

通过可滚动的结果集,您可以
移动到您想要更改的行,并且
如果类型是 TYPE_SCROLL_SENSITIVE,
您可以连续获取新值
更改后。

Am I mis-understanding something here ?

Yes. You must fetch again to get the latest state of the table, either by firing up a SELECT yourself, or calling ResultSet.refreshRow(). Moreover, read the docs of ResultSet.refreshRow() before using it, otherwise you might get unexpected results.

The doc states regarding TYPE_SCROLL_SENSITIVE,

TYPE_SCROLL_SENSITIVE

The constant indicating the type for a
ResultSet object that is scrollable
and generally sensitive to changes
made by others.

Which merely means that it would be sensitive to the changes made by others in the same ResultSet object. To understand the concept, I would advise to look at this official JDBC Tutorial: Updating Tables.

Okay, editing my post to include the specific line from the original tutorial,

With a scrollable result set, you can
move to rows you want to change, and
if the type is TYPE_SCROLL_SENSITIVE,
you can get the new value in a row
after you have changed it.

自此以后,行同陌路 2024-08-25 16:56:25

我认为您正在使用 mysql 作为数据库,这是一个已知的错误。

让我详细说明一下 -

根据 java 站点上的 Oracle 文档,TYPE_SCROLL_SENSITIVE 用于 2 个目的 -

1.Mysql 驱动程序现在可以来回移动 jdbc 结果集的指针
(否则只是向前移动),所以基本上滚动已启用
{所以现在你可以执行 resultset.previous() 并且指针将返回}

2.显示对数据库所做的更新值(内部更改)。

你被困在第二点......

看到你的程序不工作,因为你从未使用过 fetchSize() 的概念;

每当使用 jdbc 时,驱动程序都会将默认行数提取到显示的缓存中(例如:oracle 默认加载 10 行),

因此 TYPE_SCROLL_SENSITIVE 将仅显示下一次缓存重新加载的更新值。
就像数据库中有 100 行,您更新了所有行,但直到那时只提取了 10 行,因此您将随后打印更新的其他 90 行,因为驱动程序将在 9 轮缓存管理中加载这些表。

为了显式定义要获取的行数(例如将 oracle 的行数从 10 更改为 1),您可以在创建语句时显式定义 fetchSize()。(但无效地使用缓存,最终会降低速度)

因此,在初始化语句时,

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
            ResultSet.CONCUR_UPDATABLE);

添加一行 as:

stmt.setFetchSize(1); //1 is the no. of rows that will be fetched.

create resultSet as:

ResultSet rset = stmt.executeQuery("select * from persons");

验证数据:从 resultSet 打印 setFetchSize,如果它从语句传递到 resultSet,而 Sysout 则获取配置已被保存,如:

System.out.println("fetch size: " + resultSet.getFetchSize());

如果 sysout 给出 ' 1' 作为获取大小,您将看到程序的动态更新,
但如果它给出“0”,则意味着您的数据库不支持 fetchSize() 的动态初始化;

这里是mysql的问题,mysql默认会获取所有的行数到ResultSet中,因此动态内部更新时,不会获取动态值。
(内部更新是由同一程序的其他线程完成的更新)。

以下是支持我关于 sql bug 观点的 bug:

sql bugs fetchSize Bug

if you use oracle,this java doc copied from oracle documentation will just work fine:

orcale 文档 TYPE_SCROLL_SENSITIVE 示例 ResultSet5.java

import java.sql.*;

public class ResultSet5
{
  public static void main(String[] args) throws SQLException
  {
    // Load the Oracle JDBC driver
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    // Connect to the database
    // You can put a database name after the @ sign in the connection URL.
    Connection conn =
    DriverManager.getConnection ("jdbc:oracle:oci8:@", "scott", "tiger");
    // Create a Statement
    Statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, 
                                     ResultSet.CONCUR_UPDATABLE);
    // Set the statement fetch size to 1
    stmt.setFetchSize (1);
    // Query the EMP table
    ResultSet rset = stmt.executeQuery ("select EMPNO, ENAME, SAL from EMP");
    // List the result set's type, concurrency type, ..., etc
    showProperty (rset);


// List the query result 
System.out.println ("List ENO, ENAME and SAL from the EMP table: ");
while (rset.next())
{
  System.out.println (rset.getInt(1)+" "+rset.getString(2)+" "+
                      rset.getInt(3));
}
System.out.println ();

// Do some changes outside the result set
doSomeChanges (conn);

// Place the cursor right before the first row
rset.beforeFirst ();

// List the employee information again
System.out.println ("List ENO, ENAME and SAL again: ");
while (rset.next())
{
  // We expect to see the changes made in "doSomeChanges()"
  System.out.println (rset.getInt(1)+" "+rset.getString(2)+" "+
                      rset.getInt(3));
}

// Close the RseultSet
rset.close();

// Close the Statement
stmt.close();

// Cleanup
cleanup(conn);

// Close the connection
conn.close();   
  }

  /**
   * Update the EMP table.
   */ 
  public static void doSomeChanges (Connection conn)throws SQLException
  {
    System.out.println ("Update the employee salary outside the result set\n");

    Statement otherStmt = conn.createStatement ();
    otherStmt.execute ("update emp set sal = sal + 500");
    otherStmt.execute ("commit");
    otherStmt.close ();
  }

  /**
   * Show the result set properties like type, concurrency type, fetch 
   * size,..., etc.
   */
  public static void showProperty (ResultSet rset) throws SQLException
  {
    // Verify the result set type
switch (rset.getType())
{
  case ResultSet.TYPE_FORWARD_ONLY:
    System.out.println ("Result set type: TYPE_FORWARD_ONLY");
    break;
  case ResultSet.TYPE_SCROLL_INSENSITIVE:
    System.out.println ("Result set type: TYPE_SCROLL_INSENSITIVE");
    break;
  case ResultSet.TYPE_SCROLL_SENSITIVE:
    System.out.println ("Result set type: TYPE_SCROLL_SENSITIVE");
    break;
  default: 
    System.out.println ("Invalid type");
    break;
}

// Verify the result set concurrency
switch (rset.getConcurrency())
{
  case ResultSet.CONCUR_UPDATABLE:
    System.out.println 
               ("Result set concurrency: ResultSet.CONCUR_UPDATABLE");
    break;
  case ResultSet.CONCUR_READ_ONLY:
    System.out.println 
               ("Result set concurrency: ResultSet.CONCUR_READ_ONLY");
    break;
  default: 
    System.out.println ("Invalid type");
    break;
}
// Verify the fetch size
System.out.println ("fetch size: "+rset.getFetchSize ());
System.out.println ();
  }

  /* Generic cleanup.*/
      public static void cleanup (Connection conn) throws SQLException
      {
        Statement stmt = conn.createStatement ();
        stmt.execute ("UPDATE EMP SET SAL = SAL - 500");
        stmt.execute ("COMMIT");
         stmt.close ();
      }
     }

I Think you are using mysql as your db,and this is a known bug.

Let me elaborate fully-

As per Oracle documentation on the java site TYPE_SCROLL_SENSITIVE is used for 2 purposes-

1.Mysql driver can now move the jdbc result set's pointer to and fro
(which otherwise just goes in the forward direction),so basically scrolling is enabled
{so now you can do resultset.previous() and the pointer will go back}

2.To show updated values(the internal changes),made to the database.

You are stuck at the 2nd point...

See your program is not working,because you never used the concept of fetchSize();

whenever using jdbc,the driver fetches a default number of rows into the cache that is displayed(for ex:oracle loads 10 rows by default)

so TYPE_SCROLL_SENSITIVE will display the updated value of the next cache reload only.
it is like you have 100 rows in the DB,you updated all,but till then only 10 rows were fetched,so you will get the other 90 rows updated printed subsequently ,as the driver will load these tables in 9 rounds of cache management.

for explicitly defining the number of rows to be fetched(for example changing the no. of rows from 10 to 1 for oracle) you can explicitly define the fetchSize() while creating statement.(but using cache ineffectively,at the end slows the speed )

so while initializing statement as:

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
            ResultSet.CONCUR_UPDATABLE);

add a line as:

stmt.setFetchSize(1); //1 is the no. of rows that will be fetched.

create resultSet as:

ResultSet rset = stmt.executeQuery("select * from persons");

to verify the data: print setFetchSize from resultSet,if it passes from statement to resultSet while Sysout than the fetching configuration has been saved,as:

System.out.println("fetch size: " + resultSet.getFetchSize());

if the sysout gives '1' as fetch size,you will see your dynamic updates from the program as it is,
but if it gives '0' that means your DB doesnot support dynamic initialization of fetchSize();

Here is the problem with mysql,mysql by default fetches all the number of rows into the ResultSet,and thus the dynamic internal update,does not fetch the dynamic values.
(internal update is the update done by some other thread of the same program).

Here is the bug supporting my point on sql bugs:

sql bugs fetchSize Bug

if you use oracle,this java doc copied from oracle documentation will just work fine:

orcale docs TYPE_SCROLL_SENSITIVE example ResultSet5.java

import java.sql.*;

public class ResultSet5
{
  public static void main(String[] args) throws SQLException
  {
    // Load the Oracle JDBC driver
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    // Connect to the database
    // You can put a database name after the @ sign in the connection URL.
    Connection conn =
    DriverManager.getConnection ("jdbc:oracle:oci8:@", "scott", "tiger");
    // Create a Statement
    Statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, 
                                     ResultSet.CONCUR_UPDATABLE);
    // Set the statement fetch size to 1
    stmt.setFetchSize (1);
    // Query the EMP table
    ResultSet rset = stmt.executeQuery ("select EMPNO, ENAME, SAL from EMP");
    // List the result set's type, concurrency type, ..., etc
    showProperty (rset);


// List the query result 
System.out.println ("List ENO, ENAME and SAL from the EMP table: ");
while (rset.next())
{
  System.out.println (rset.getInt(1)+" "+rset.getString(2)+" "+
                      rset.getInt(3));
}
System.out.println ();

// Do some changes outside the result set
doSomeChanges (conn);

// Place the cursor right before the first row
rset.beforeFirst ();

// List the employee information again
System.out.println ("List ENO, ENAME and SAL again: ");
while (rset.next())
{
  // We expect to see the changes made in "doSomeChanges()"
  System.out.println (rset.getInt(1)+" "+rset.getString(2)+" "+
                      rset.getInt(3));
}

// Close the RseultSet
rset.close();

// Close the Statement
stmt.close();

// Cleanup
cleanup(conn);

// Close the connection
conn.close();   
  }

  /**
   * Update the EMP table.
   */ 
  public static void doSomeChanges (Connection conn)throws SQLException
  {
    System.out.println ("Update the employee salary outside the result set\n");

    Statement otherStmt = conn.createStatement ();
    otherStmt.execute ("update emp set sal = sal + 500");
    otherStmt.execute ("commit");
    otherStmt.close ();
  }

  /**
   * Show the result set properties like type, concurrency type, fetch 
   * size,..., etc.
   */
  public static void showProperty (ResultSet rset) throws SQLException
  {
    // Verify the result set type
switch (rset.getType())
{
  case ResultSet.TYPE_FORWARD_ONLY:
    System.out.println ("Result set type: TYPE_FORWARD_ONLY");
    break;
  case ResultSet.TYPE_SCROLL_INSENSITIVE:
    System.out.println ("Result set type: TYPE_SCROLL_INSENSITIVE");
    break;
  case ResultSet.TYPE_SCROLL_SENSITIVE:
    System.out.println ("Result set type: TYPE_SCROLL_SENSITIVE");
    break;
  default: 
    System.out.println ("Invalid type");
    break;
}

// Verify the result set concurrency
switch (rset.getConcurrency())
{
  case ResultSet.CONCUR_UPDATABLE:
    System.out.println 
               ("Result set concurrency: ResultSet.CONCUR_UPDATABLE");
    break;
  case ResultSet.CONCUR_READ_ONLY:
    System.out.println 
               ("Result set concurrency: ResultSet.CONCUR_READ_ONLY");
    break;
  default: 
    System.out.println ("Invalid type");
    break;
}
// Verify the fetch size
System.out.println ("fetch size: "+rset.getFetchSize ());
System.out.println ();
  }

  /* Generic cleanup.*/
      public static void cleanup (Connection conn) throws SQLException
      {
        Statement stmt = conn.createStatement ();
        stmt.execute ("UPDATE EMP SET SAL = SAL - 500");
        stmt.execute ("COMMIT");
         stmt.close ();
      }
     }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文