2008-10-17 68 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