2015-10-21 185 views
1

我使用Oracle 11g(它可能對解決方案有影響)。我有如下版本的表格。我想從這個表中選擇由原子操作組成,插入到另一個表(取決於前者的狀態)並更新前一個表的狀態。樂觀鎖定的原子

我想簡單的解決方案(簡單的問題簡單的解決方案?),原子,我想避免死鎖。我選擇樂觀鎖定策略。

所以,我有這樣的表

CREATE TABLE table (
    id int, 
    version int, 
    state varchar(20) 
); 

僞代碼我有這樣的事情:

Line 1: SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
Line 2: START TRANSACTION; 
Line 3: SELECT state as S, version as V from table where id = X; 
Line 4: if (S == 'TODO') then 
Line 5:  INSERT INTO other_table ... 
Line 6:  UPDATE table SET state = 'DONE', version = version + 1 WHERE id = X and version = V 
Line 7: COMMIT; 

據我瞭解SQL事務,另一個線程可以執行第6行之間的相同的代碼塊和第一胎的第七胎。然後(考慮隔離級別=讀取提交)我有兩個插入到我不想要的other_table

我怎樣才能使這個代碼塊真的原子?

我想避免鎖定行和序列化隔離級別(死鎖)。

+0

如果你的DBMS使用樂觀併發控制,你永遠不會得到任何死鎖。事務是一個原子操作。 – jarlh

+0

您是否有特定的RDBMS? –

+0

是的,它是Oracle 11g。 – emstol

回答

3

不需要混淆隔離級別,您可以先執行UPDATE,如果更新成功,請執行INSERT。該更新將鎖定受影響的行(oracle documentation here),因此另一個會話將被阻止,直到第一個會話關閉其事務。

例如用PL/SQL:

BEGIN 
    UPDATE t 
    SET state = 'DONE', version = version + 1 
    WHERE id = x 
    AND state = 'TODO'; 

    IF(SQL%FOUND) THEN 
    dbms_output.put_line('INSERT HERE'); 
    END IF; 
END; 
/
+0

嗯..你確定更新鎖定受影響的行直到事務結束?你能分享一些鏈接到文檔嗎? – emstol

+0

當然,看看[自動鎖定DML操作](http://docs.oracle.com/cd/E11882_01/server.112/e41084/ap_locks001.htm#SQLRF55502)。您也可以通過在兩個SQL * Plus會話中執行代碼而不關閉事務來自行嘗試。 –