我需要执行一个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
?答案 0 :(得分:4)
这里可能会有大量技术和概念发挥作用,当您开始考虑多线程/多请求应用程序时,事情开始变得相当棘手。
正如Iassevk所说,你应该考虑使用Transactions来确保你的更新的原子性 - 一个非常低级的例子是做一些事情:
...
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)
但是,这不会解决您的第二个问题,即尝试更新同一个表的两种竞争方法 - 竞争条件。在我看来,这里有两种主要方法 - 每种方法都有它的优点和缺点。
最简单的方法是Lock the table - 这需要最少的代码更改,但有一个很大的缺点。假设,与大多数应用程序一样,更多的是读取写入:锁定表将阻止所有其他用户查看数据,代码可能会挂起,等待锁定在连接超时之前释放踢出并抛出异常。
更复杂的方法是确保以线程安全的方式实现执行这些更新的方法。为此:
答案 1 :(得分:0)
使用交易。
答案 2 :(得分:0)
如果任何其他进程通过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