以原子方式更新多行数据

4

我需要以原子方式执行选择,然后更新 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

这里涉及到许多技术和概念,当考虑多线程/多请求应用程序时,情况变得非常棘手。

正如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)
然而,这并不能解决您的第二个问题,即两个竞争方法尝试更新同一个表 - 竞争条件。在我看来,这里有两种主要方法 - 每种方法都有其优点和缺点。
最简单的方法是锁定表 - 这将需要最少的代码更改,但有一个相当大的缺点。假设与大多数应用程序一样,它更多地读取而不是写入:锁定表将阻止所有其他用户查看数据,有可能代码会挂起,等待锁定释放,然后连接超时启动并抛出异常。
更复杂的方法是确保执行这些更新的方法以线程安全的方式实现。为此:
  • 所有对该表的更新都通过一个类进行
  • 该类实现单例模式,或将更新方法公开为静态方法
  • 更新方法使用同步关键字以防止竞争条件

谢谢。我正在寻找一种使用JDBC(或至少标准SQL)锁定表、具体行甚至单个单元格的方法。我想这是不可能的。 - Guido

0

使用事务。


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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接