2009-11-27 109 views
1

我有2個程序在2個不同的機器上運行。
每個程序都有一個名爲updateRecord方法,做以下兩兩件事:
1.執行某條記錄ž
2. SELECT查詢請在相同的記錄一個UPDATE查詢。併發/同步問題

如果這兩個查詢在同一個事務中(在beginTransaction和commitTransaction之間)它確保正確執行嗎?

即,以下操作順序失敗成功執行?

  1. PROG-1 SELECT
  2. PROG-2 SELECT
  3. PROG-1 UPDATE
  4. PROG-2 UPDATE

OR

  1. PROG-1 SELECT
  2. Prog-1 UPDATE
  3. PROG-1 SELECT
  4. PROG-2 UPDATE
  5. PROG-1 COMMIT
  6. PROG-2 COMMIT
+0

已更新標籤..... – user855 2009-11-27 07:06:16

+0

如果您真的關心併發性,請使用整數數據類型實現版本列。然後確保您的更新/刪除語句使用該值來確保您處理最新的記錄。 – 2009-11-27 21:53:15

回答

1

兩臺機器永遠不會使用相同的交易。如果在存儲過程中執行SELECT & UPDATE,它們將在同一個事務中。如果SELECT & UPDATE查詢是作爲單獨的語句運行,那麼下面的可能性:

  1. PROG-1 SELECT
  2. PROG-2 SELECT
  3. PROG-1 UPDATE
  4. PROG-2 UPDATE

根據數據庫隔離級別,機器#2的select可能在運行機器#1的UPDATE之前查看數據。 IIRC,默認情況下Oracle會是這種情況。

這是411 on Oracle's Isolation Levels, per AskTom

對於MySQL,請使用SET TRANSACTION命令。有關MySQL隔離級別支持的更多信息,請參閱this link

+0

2號機器不使用相同的交易。 我說2個查詢是在同一個交易 – user855 2009-11-27 06:59:14

+0

和這個隔離水平如何設置? – user855 2009-11-27 06:59:49

3

當程序選擇它時,程序需要鎖定記錄 - 例如,使用SELECT FOR UPDATE語法。這樣,記錄將被鎖定,直到UPDATE完成。

+0

鎖定發生在數據庫中,而不是應用程序。而且有些dbs不支持少列鎖。 – 2009-11-27 21:51:56

+0

感謝OMG小馬 - 我的答案是針對Oracle的。是的,它是鎖定行而不是應用程序的數據庫 - SELECT FOR UPDATE語法是應用程序向數據庫請求鎖的方式。 – 2009-11-29 07:41:57

2

如前所述,使用SELECT ... FOR UPDATE有助於鎖定行,直到事務被提交(或回滾)爲止。

你不需要兩臺機器來測試它。通過使用兩個不同的會話(例如通過運行兩個不同的SQL * Plus實例)並在兩個會話中以特定順序同時運行您的查詢,您將能夠重現併發問題(如果有的話)。

在這種情況下,你可以運行:

Session1: SELECT z AS sel_z -- sel_z = 0 
Session1: UPDATE z = sel_z + 1 
Session2: SELECT z AS sel_z -- (1) sel_z = 0 because Session1 is uncommitted 
Session2: UPDATE z = sel_z + 1 
Session1: COMMIT 
Session2: COMMIT 
Session1: SELECT z AS sel_z -- sel_z = 1 
Session2: SELECT z AS sel_z -- sel_z = 1 

的問題是在(1),會話2不見值由SESSION1改變,因爲他們都不敢承諾。

我的建議是不要考慮改變TX隔離級別,考慮鎖定適當的資源。