Поведение ResultSet.TYPE_SCROLL_SENSITIVE

Меня смущает поведение ResultSet типа TYPE_SCROLL_SENSITIVE.

Мое понимание этого таково:

  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"));
}

person divesh premdeep    schedule 19.01.2010    source источник
comment
Кроме того, я только что заметил, что JDBC предоставляет еще один метод ResultSet.refreshRow(). Добавление этого в код (непосредственно перед шагом 4) дает мне желаемый результат. Какой тогда смысл в TYPE_SCROLL_SENSITIVE?   -  person divesh premdeep    schedule 19.01.2010
comment
RefreshRow() просто означает запуск запроса к БД для получения последнего состояния.   -  person Adeel Ansari    schedule 19.01.2010
comment
TYPE_SCROLL_SENSITIVE вызывает refreshRow неявно. Подробнее о реализации Oracle см.   -  person Marmite Bomber    schedule 10.02.2019


Ответы (2)


Я что-то здесь неправильно понимаю?

Да. Вы должны снова выполнить выборку, чтобы получить последнее состояние таблицы, либо самостоятельно запустив SELECT, либо вызвав ResultSet.refreshRow(). Кроме того, прочитайте документы ResultSet.refreshRow()< /a> перед его использованием, иначе вы можете получить неожиданные результаты.

В документе говорится о TYPE_SCROLL_SENSITIVE,

TYPE_SCROLL_SENSITIVE

Константа, указывающая тип объекта ResultSet, который можно прокручивать и который обычно чувствителен к изменениям, внесенным другими.

Это просто означает, что он будет чувствителен к изменениям, сделанным другими в том же объекте ResultSet. Чтобы понять концепцию, я бы посоветовал взглянуть на это официальное JDBC Tutorial: Обновление таблиц.

Хорошо, редактирую свой пост, чтобы включить конкретную строку из исходного урока,

С прокручиваемым набором результатов вы можете перемещаться к строкам, которые хотите изменить, и, если тип TYPE_SCROLL_SENSITIVE, вы можете получить новое значение в строке после того, как вы его изменили.

person Adeel Ansari    schedule 19.01.2010
comment
Я до сих пор не понимаю :(. вы можете получить новое значение в строке после того, как вы его изменили. Означает ли это, что если я выполню ResultSet.updateXXX(columnIndex, val), я могу получить обновленное значение, выполнив ResultSet.getXXX (индекс столбца) ? - person divesh premdeep; 19.01.2010
comment
Да, точно. С другим, TYPE_SCROLL_INSENSITIVE, дело обстоит иначе. - person Adeel Ansari; 19.01.2010
comment
Возможно проблема в реализации драйвера. Не уверена. - person Adeel Ansari; 19.01.2010
comment
@Adeel Ansari, не могли бы вы пересмотреть мой вопрос я вижу необновляемый, когда я вызываю обновление набора результатов"> stackoverflow.com/questions/25582698/ - person gstackoverflow; 30.08.2014

Я думаю, что вы используете mysql в качестве базы данных, и это известная ошибка.

Позвольте мне подробно остановиться на

Согласно документации Oracle на сайте Java, TYPE_SCROLL_SENSITIVE используется для двух целей:

1. Драйвер Mysql теперь может перемещать указатель набора результатов jdbc туда и сюда (который в противном случае просто идет в прямом направлении), поэтому в основном включена прокрутка {так что теперь вы можете сделать resultset.previous(), и указатель вернется}

2. Чтобы показать обновленные значения (внутренние изменения), внесенные в базу данных.

Вы застряли на 2-м пункте...

Посмотрите, ваша программа не работает, потому что вы никогда не использовали концепцию fetchSize();

всякий раз, когда используется jdbc, драйвер извлекает количество строк по умолчанию в отображаемый кеш (например, oracle загружает 10 строк по умолчанию)

поэтому TYPE_SCROLL_SENSITIVE будет отображать только обновленное значение следующей перезагрузки кеша. это похоже на то, что у вас есть 100 строк в БД, вы обновили все, но до этого были извлечены только 10 строк, поэтому вы получите остальные 90 обновленных строк, распечатанные впоследствии, поскольку драйвер загрузит эти таблицы в 9 раундах управления кешем.

для явного определения количества извлекаемых строк (например, изменение количества строк с 10 до 1 для оракула) вы можете явно определить fetchSize() при создании оператора (но использование кеша неэффективно, в конце замедляет скорость )

поэтому при инициализации оператора как:

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

добавить строку как:

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

создать набор результатов как:

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

для проверки данных: напечатайте setFetchSize из набора результатов, если он переходит от оператора к набору результатов во время Sysout, тогда конфигурация выборки была сохранена, как:

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

если sysout дает «1» в качестве размера выборки, вы увидите свои динамические обновления из программы как есть, но если он дает «0», это означает, что ваша БД не поддерживает динамическую инициализацию fetchSize();

Вот проблема с mysql, mysql по умолчанию извлекает все количество строк в ResultSet и, следовательно, динамическое внутреннее обновление не извлекает динамические значения. (внутреннее обновление — это обновление, выполненное другим потоком той же программы).

Вот ошибка, подтверждающая мою точку зрения на ошибки sql:

баг ошибки fetchSize

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 ();
      }
     }
person bondkn    schedule 30.08.2014