Вопрос

Мне нужно выполнить select, а затем обновить некоторые строки в 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 ?
Это было полезно?

Решение

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

Как заявил 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 )

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

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

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

  • Все обновления для этой таблицы проходят через один класс
  • Этот класс реализует одноэлементный шаблон или предоставляет методы обновления как статические методы
  • Методы обновления используют Синхронизированный ключевое слово для предотвращения условий гонки

Другие советы

Используйте транзакции.

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

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

select cola, colB from tabA for update;

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top