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



Используйте транзакции.
Вероятно, здесь вступает в игру целая куча технологий и концепций, и все начинает становиться довольно липким, когда вы начинаете рассматривать многопоточные / многопоточные приложения.
Как заявил Яссевк, вам следует изучить возможность использования Сделки, чтобы гарантировать атомарный характер ваших обновлений - очень низкоуровневым примером было бы сделать что-то вроде:
...
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)
Однако это не решит вашу вторую проблему, которая заключается в том, что два конкурирующих метода пытаются обновить одну и ту же таблицу - условие гонки. На мой взгляд, здесь есть два основных подхода, каждый из которых имеет свои достоинства и недостатки.
Самый простой подход - это Заблокируйте стол - это потребует минимальных изменений кода, но имеет довольно большой недостаток. Исходя из предположения, что, как и в большинстве приложений, больше читать, чем писать: блокировка таблицы не позволит всем другим пользователям просматривать данные, с вероятностью зависания кода в ожидании снятия блокировки до истечения времени ожидания соединения. срабатывает и выдает исключение.
Более сложный подход состоит в том, чтобы гарантировать, что методы для выполнения этих обновлений реализованы потокобезопасным способом. С этой целью:
What happens if any other process has changed the database row that you are updating via updateRow() ? Is there any way to lock the rows in the 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
Спасибо. Я искал способ заблокировать таблицу, конкретную строку или даже одну ячейку с помощью JDBC (или, по крайней мере, стандартного SQL). Полагаю, это невозможно.