以原子方式更新多行

Posted

技术标签:

【中文标题】以原子方式更新多行【英文标题】:Update more than one row atomically 【发布时间】:2008-10-17 08:26:44 【问题描述】:

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

【问题讨论】:

【参考方案1】:

可能有一大堆技术和概念在这里发挥作用,当您开始考虑多线程/多请求应用程序时,事情开始变得相当棘手。

正如 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 - 这需要最少的代码更改,但有一个很大的缺点。假设与大多数应用程序一样,读多于写:锁定表将阻止所有其他用户查看数据,代码可能会挂起,等待锁定在连接超时之前释放启动并引发异常。

更复杂的方法是确保执行这些更新的方法以线程安全的方式实现。为此:

此表的所有更新都通过一个类 该类实现单例模式,或将更新方法公开为静态方法 更新方法使用 Synchronized 关键字来防止竞争条件

【讨论】:

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

使用事务。

【讨论】:

【参考方案3】:

如果任何其他进程更改了您通过 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

【讨论】:

以上是关于以原子方式更新多行的主要内容,如果未能解决你的问题,请参考以下文章

Java compareAndSet 以原子方式更新 BST 中的引用

JDK原子操作类

架构模式: 事务发件箱

线程 lambda 中的原子更新

原子片段:原子编辑器中的多行片段

firebase - 在多个位置进行原子删除