2017-07-01 58 views
1

我完全不理解SELECT FOR UPDATE的鎖定功能。Oracle SELECT FOR UPDATE - 演示?

這是我試過的。

CREATE TABLE ACCOUNT_TAB (
    ACC_ID int NOT NULL PRIMARY KEY, 
    BALANCE int NOT NULL 
); 

INSERT INTO ACCOUNT_TAB 
VALUES(1, 100); 

SELECT * FROM ACCOUNT_TAB FOR UPDATE; 
SELECT * FROM ACCOUNT_TAB; 

兩個SELECT都將檢索該行,但不應該第一個查詢鎖定ACCOUNT_TAB表中的行嗎?

我已閱讀了有關會話的內容:來自同一個會話的查詢並不關心鎖定。我可以以某種方式在單個腳本文件中演示鎖定功能嗎?例如,我可以在一個腳本中運行兩個不同的會話,所以第二個調用將檢索一個錯誤,指出該行已被鎖定?

+3

鎖定只是阻止更新或刪除,而不是選擇 –

+0

好了,但仍是有一些方法來證明在一個腳本文件上的鎖?如果我選擇更新,然後執行兩個更新,則當然會允許這兩個更新,因爲我請求選擇進行更新。也許有可能同時運行2個交易? – Max

+0

其他會話將不會看到轉換器,直到您提交'commit' – are

回答

3

您的原始實驗未能證明鎖定,因爲在Oracle中寫入不會阻止讀取。 FOR UPDATE子句允許我們避免兩個會話嘗試寫入同一記錄的情況;任何數量的會話都可以讀取記錄。 「

」好吧,但仍然有一些方法可以演示單個腳本文件中的鎖定嗎?「

是。這裏是一個局部過程,它使用autonomous_transaction編譯來模擬多用戶環境的腳本:

declare 
    procedure p1 (p_id in number) is 
     pragma autonomous_transaction; 
     cursor c23 is 
      select * from t23 
      where id = p_id 
      for update nowait; 
     r23 c23%rowtype; 
    begin 
     dbms_output.put_line('nested transaction'); 
     open c23; 
     fetch c23 into r23; 
     update t23 
     set col2 = col2 * 2; 
     close c23; 
     commit; 
    exception 
     when others then 
      dbms_output.put_line(sqlerrm); 
    end; 

begin 
    update t23 
    set col1 = 2 
    where id = 1; 

    p1 (1); 

    commit; 
end; 
/

第一個UPDATE語句發出的鎖,這會導致程序調用失敗,因爲它不能獲得鎖定(由於使用NOWAIT子句):

... 
    30 end; 
    31/
nested transaction 
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 

PL/SQL procedure successfully completed. 

SQL> 
+0

我有一個問題給你,我很感激你的回答。原來的問題是關於'SELECT FOR UPDATE',涉及顯式鎖定。所以我們假設我們使用'SELECT FOR UPDATE'而不是'update t23',你將如何啓動另一個自治事務(在不釋放鎖定的情況下調用'p1')。第二個問題:如果你之前設法啓動另一個AT釋放't23'上的鎖定,是不是會導致死鎖,因爲主交易劇照仍然擁有獨佔鎖定? – fg78nc

1

RDBMS將在SELECT FOR UPDATE語句標識的所有行上獲得獨佔的行級鎖,因此只有您是唯一允許更新它們的行。這意味着除非您執行COMMIT或ROLLBACK,否則其他RDBMS客​​戶端將無法更改任何此記錄。因此,如果要測試它的工作方式,請創建兩個單獨的客戶端連接,並首先嚐試在一個會話中鎖定記錄,然後嘗試在另一個會話中更新相同的記錄。