2008-10-17 88 views
4

我需要执行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中的行?

回答

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

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

  • 所有此表的更新通过单个类
  • 即类实现一个Singleton模式,或公开的更新方法如静态方法
  • 的更新方法利用Synchronized关键字来防止竞争条件
+0

谢谢。我正在寻找一种方法来锁定表,一个具体的行,甚至使用JDBC(或至少标准的SQL)单个单元格。我想这是不可能的。 – 2008-10-17 18:09:38

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