原子更新多行

问题描述 投票:0回答:3

我需要执行选择,然后以原子方式更新

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
    中的行?
java database jdbc transactions
3个回答
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)

但是,这不会解决您的第二个问题,即两种竞争方法试图更新同一个表 - 竞争条件。在我看来,这里有两种主要方法 - 每种方法都有其优点和缺点。

最简单的方法是锁定表 - 这需要最少的代码更改,但有一个很大的缺点。假设与大多数应用程序一样,读取多于写入:锁定表将阻止所有其他用户查看数据,代码可能会挂起,等待连接超时之前释放锁启动并抛出异常。

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.