Обновить несколько строк атомарно - PullRequest
4 голосов
/ 17 октября 2008

Мне нужно выполнить выборку, а затем обновить некоторые строки в ResultSet атомарным способом.

Код, который я использую, выглядит (упрощенно):

stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT ...");

while (rs.next()) {
    if (conditions_to_update) {
        rs.updateString(...);
        rs.updateRow();
    }
}
  • Могу ли я гарантировать, что обновления будут выполняться атомарно? Если нет, то как я могу это заверить?
  • Что произойдет, если какой-либо другой процесс изменил строку базы данных, которую вы обновляете с помощью updateRow()? Есть ли способ заблокировать строки в ResultSet?

Ответы [ 3 ]

4 голосов
/ 17 октября 2008

Здесь, вероятно, присутствует целая куча технологий и концепций, и вещи начинают становиться довольно запутанными, когда вы начинаете рассматривать многопоточные / многопользовательские приложения.

Как заявил Iassevk, вы должны изучить возможность использования транзакций для обеспечения атомарной природы ваших обновлений - очень низкоуровневым примером будет что-то вроде:

...
con.setAutoCommit(false);
try {
  while (rs.next()) {
    if (conditions_to_update) {
      rs.updateString(...);
      rs.updateRow();
    }
  }
  con.setAutoCommit(true);
} catch (Exception ex) {
  //log the exception and rollback
  con.rollback();
} finally {
  con.close();
}

Все обновления будут затем объединены в одну транзакцию. Если какое-либо из обновлений сгенерировало исключение (например, недопустимое значение или сбой соединения в процессе получения результатов), весь лот будет откатан. (Наконец-то добавлено, потому что я чемпион этого; p)

Это, однако, не решит вашу вторую проблему - два конкурирующих метода, пытающихся обновить одну и ту же таблицу - условие гонки. На мой взгляд, здесь есть два основных подхода - у каждого есть свои достоинства и недостатки.

Самый простой подход - Блокировка таблицы - это потребует минимальных изменений кода, но имеет довольно большой недостаток. Работая в предположении, что, как и в большинстве приложений, это больше чтение, чем запись: блокировка таблицы не позволит всем другим пользователям просматривать данные с вероятностью, что код зависнет, ожидая снятия блокировки до истечения времени ожидания соединения пинает и выдает исключение.

Более сложный подход заключается в обеспечении того, чтобы методы для выполнения этих обновлений были реализованы потокобезопасным способом. Для этого:

  • Все обновления для этой таблицы проходят через один класс
  • Этот класс реализует шаблон Singleton или предоставляет методы обновления как статические методы
  • Методы обновления используют ключевое слово Synchronized , чтобы предотвратить состояние гонки
0 голосов
/ 17 октября 2008

Что произойдет, если какой-либо другой процесс изменил строку базы данных, которую вы обновляете с помощью updateRow ()? Есть ли способ заблокировать строки в ResultSet?

В Oracle вы можете пометить определенные строки для обновления, введя следующий SQL.

select cola, colB from tabA for update;

Следующая транзакция / поток / приложение, которое пытается обновить эту строку, получит исключение. см. это для более подробной информации - http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4530093713805

0 голосов
/ 17 октября 2008

Использовать транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...