oracle資料庫版讀者寫者問題

pingley發表於2012-04-12
oracle資料庫版讀者寫者問題
     透過讀者寫者的問題,可以向我們揭示oracle資料庫神秘又複雜的鎖機制。鎖機制透過控制資料庫的併發,從而保證資料的一致性與完整性。
讀者:查詢一個資源。寫者:修改一個資源。
以下是對oracle版讀者寫者問題的總結:
1、一條記錄只有當寫者修改的時候才會被鎖住。
比如update一條記錄,事務會請求鎖住這一行(僅僅是這一行)。這種行級鎖可以最小化對資料庫資源的競爭,提高更好的併發性。正常情況下不會升級行級鎖到block 或者 table 級。
2、鎖定了某條記錄的寫者會阻塞(block)併發的同樣需要鎖定該條記錄的寫者。
3、讀者不會阻塞寫者。
因為讀者不會鎖住某任何一行。除非顯式的發出select ...for update 語句。該語句會鎖住select 語句所讀的記錄。
4、寫者不會阻塞讀者。
當表中的某條記錄因為寫者的操作而改變以後。資料庫使用undo 資料來提供給讀者一個一致性的記錄檢視。雖然關於oracle 版的讀者寫者問題只有那麼幾段話,但是我個人認為這些都是精華。
oracle 把很多關於鎖的機制,抽象融入了其中。下面用一個列子來揭示讀者寫者問題。
SQL> select sid from V$mystat where rownum = 1;
       SID
----------
        47
在session 1 中發出如下的update 語句,不提交。
SQL> update employees
  2  set salary = salary + 1000
  3  where employee_id = 100;
1 row updated.
SQL> select sid from V$mystat where rownum = 1;
       SID
----------
         1
在session 2 中發出如下的update 語句。情況是阻塞在那邊,一直在等待。所以我把該語句cancel 了。
SQL> update employees
  2  set salary = salary + 1000
  3  where employee_id = 100;
^Cupdate employees
       *
ERROR at line 1:
ORA-01013: user requested cancel of current operation
再在session 2 中發出如下的update 語句,不提交。
SQL> update employees
  2  set salary = salary + 1000
  3  where employee_id = 200;
1 row updated.
從上面的示例中我們可以證明oracle版讀者寫者問題中的:
1、一條記錄只有當寫者修改的時候才會被鎖住。
2、鎖定了某條記錄的寫者會阻塞(block)併發的同樣需要鎖定該條記錄的寫者。session 1 中的update 語句鎖住了employee_id=100的記錄。所以阻塞了在session 2 中的同樣需要鎖住employee_id=100的記錄的update 語句。但是session 2卻可以透過執行update 語句來鎖定其他他所需要鎖住的記錄。比如這裡的employee_id=200 的那條記錄。說明session 1 確實只是鎖住了他所需要修改的行而不是所有的行或者整張表。
我們繼續往下走。在session 1中發出如下的select 語句。
SQL> select employee_id,first_name,last_name,salary
  2  from employees
  3  where employee_id = 100;
EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        100 Steven               Smith                           6540
在session 2 中發出相同的select 語句。
SQL>  select employee_id,first_name,last_name,salary
  2   from employees
  3   where employee_id = 100;
EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        100 Steven               Smith                           5540
此時session 1 中的事務還沒有提交,employee_id = 100 的記錄還是被鎖住了,但是卻不影響讀者查詢,說明:寫者不阻塞讀者。值得注意的是讀者讀出來的資料。session 2中的查詢結果沒有反映session 1中的update...employee_id = 100 的記錄的資訊。因為session 1 中的update 還沒有提交,鎖還沒有釋放,修改還未生效。資料庫透過使用undo data給session 2中的讀者提供一個一致性的檢視。
至於讀者不阻塞寫者我想這一點很好理解不作附加的解釋。只是要來說說那個select...for update語句。先把session1 ,session 2中的修改rollback.以免影響後續的操作。
在session 1 中發出如下的select ... for update 語句。
SQL> select employee_id,first_name,last_name,salary
  2  from employees
  3  where employee_id < 110
  4  for update;
EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        100 Steven               Smith                           5540
        101 Neena                Kochhar                         5540
        102 Lex                  De Haan                         5540
        103 Alexander            Hunold                          5540
        104 Bruce                Ernst                           5540
        105 David                Austin                          5540
        106 Valli                Pataballa                       5540
        107 Diana                Lorentz                         5540
        108 Nancy                Greenberg                       5540
        109 Daniel               Faviet                          5540
10 rows selected.
在session 2 中發出如下的update 語句阻塞在那邊,卡在那邊。所以我cancel了。
SQL> update employees
  2  set salary = salary + 100
  3  where employee_id = 105;
^Cupdate employees
       *
ERROR at line 1:
ORA-01013: user requested cancel of current operation
因為select ... for update 語句相當於是寫者,根據給定的條件鎖住了相應的行。
我覺得如果要學習oracle 的鎖機制從讀者寫者問題開始學習,可以先獲得一個感性的認識,然後在深入oracle具體的鎖機制。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26110315/viewspace-720969/,如需轉載,請註明出處,否則將追究法律責任。

相關文章