1. 程式人生 > >oracle 資料庫事務,提交,回滾,儲存點,表的鎖定,隱式鎖,顯示鎖,寫鎖,讀鎖,排他鎖,共享鎖

oracle 資料庫事務,提交,回滾,儲存點,表的鎖定,隱式鎖,顯示鎖,寫鎖,讀鎖,排他鎖,共享鎖

資料庫事務的概念
事務是由相關操作構成的一個完整的操作單元。兩次連續成功的COMMIT或ROLLBACK之間的操作,稱為一個事務。在一個事務內,資料的修改一起提交或撤銷,如果發生故障或系統錯誤,整個事務也會自動撤銷。
比如,我們去銀行轉賬,操作可以分為下面兩個環節:
(1) 從第一個賬戶劃出款項。
(2) 將款項存入第二個賬戶。
整個交易過程,可以看作是一個事物,成功則全部成功,失敗則需要全部撤消,這樣可以避免當操作的中間環節出現問題時,產生資料不一致的問題。
資料庫事務是一個邏輯上的劃分,有的時候並不是很明顯,它可以是一個操作步驟,也可以是多個操作步驟。
我們可以這樣理解資料庫事物:對資料庫所做的一系列修改,在修改過程中,暫時不寫入資料庫,而是快取起來,使用者在自己的終端可以預覽變化,直到全部修改完成,並經過檢查確認無誤後,一次性提交併寫入資料庫,在提交之前,必要的話所做的修改都可以取消。提交之後,就不能撤銷,提交成功後其他使用者才可以通過查詢瀏覽資料的變化。
以事務的方式對資料庫進行訪問,有如下的優點:
* 把邏輯相關的操作分成了一個組。
* 在資料永久改變前,可以預覽資料變化。
* 能夠保證資料的讀一致性。

資料庫事務的應用

資料庫事務處理可分為隱式和顯式兩種。顯式事務操作通過命令實現,隱式事務由系統自動完成提交或撤銷(回退)工作,無需使用者的干預。
隱式提交的情況包括:當用戶正常退出SQL*Plus或執行CREATE、DROP、GRANT、REVOKE等命令時會發生事務的自動提交。

還有一種情況,如果把系統的環境變數AUTOCOMMIT設定為ON(預設狀態為OFF),則每當執行一條INSERT、DELETE或UPDATE命令對資料進行修改後,就會馬上自動提交。設定命令格式如下:
SET AUTOCOMMIT ON/OFF
隱式回退的情況包括:當異常結束SQL*Plus或系統故障發生時,會發生事務的自動回退。
顯式事務處理的資料庫事務操作語句有3條,
COMMIT:資料庫事務提交,將變化寫入資料庫
ROLLBACK:資料庫事務回退,撤銷對資料的修改
SAVEPOINT:建立儲存點,用於事務的階段回退

COMMIT操作把多個步驟對資料庫的修改,一次性地永久寫入資料庫,代表資料庫事務的成功執行。ROLLBACK操作在發生問題時,把對資料庫已經作出的修改撤消,回退到修改前的狀態。在操作過程中,一旦發生問題,如果還沒有提交操作,則隨時可以使用ROLLBACK來撤消前面的操作。SAVEPOINT則用於在事務中間建立一些儲存點,ROLLBACK可以使操作回退到這些點上邊,而不必撤銷全部的操作。一旦COMMIT完成,就不能用ROLLBACK來取消已經提交的操作。一旦ROLLBACK完成,被撤消的操作要重做,必須重新執行相關操作語句。

如何開始一個新的事務呢?一般情況下,開始一個會話(即連線資料庫),執行第一條SQL語句將開始一個新的事務,或執行COMMIT提交或ROLLBACK撤銷事務,也標誌新的事務的開始。另外,執行DDL(如CREATE)或DCL命令也將自動提交前一個事務而開始一個新的事務。

資料在修改的時候會對記錄進行鎖定,其他會話不能對鎖定的記錄進行修改或加鎖,只有當前會話提交或撤銷後,記錄的鎖定才會釋放。

觀察資料的讀一致性

步驟1:顯示剛插入的僱員小馬:
Sql程式碼  收藏程式碼
  1. SELECT empno,ename FROM emp WHERE empno=3000;  

執行結果:
     Sql程式碼  收藏程式碼
  1. EMPNO ENAME  
  2.         ------------------ -----------
  3.             3000   小馬  

步驟2:刪除僱員小馬:
Sql程式碼  收藏程式碼
  1. DELETEFROM emp WHERE empno=3000;  

執行結果:
已刪除 1 行。
步驟3:再次顯示該僱員,顯示結果為該僱員不存在:
Sql程式碼  收藏程式碼
  1. SELECT empno,ename FROM
     emp WHERE empno=3000;  

執行結果:
未選定行
步驟4:另外啟動第2個SQL*Plus,並以SCOTT身份連線。執行以下命令,結果為該記錄依舊存在。
Sql程式碼  收藏程式碼
  1. SELECT empno,ename FROM emp WHERE empno=3000;  

執行結果:
     Sql程式碼  收藏程式碼
  1. EMPNO ENAME  
  2.         ------------------ -----------
  3.               3000   小馬  

步驟5:在第1個SQL*Plus中提交刪除:
Sql程式碼  收藏程式碼
  1. COMMIT;  

執行結果:
提交完成。
步驟6:在第2個SQL*Plus中再次顯示該僱員,顯示結果與步驟3的結果一致:
Sql程式碼  收藏程式碼
  1. SELECT empno,ename FROM emp WHERE empno=3000;  

執行結果:
未選定行 
說明:在以上訓練中,當第1個SQL*Plus會話刪除小馬後,第2個SQL*Plus會話仍然可以看到該僱員,直到第1個SQL*Plus會話提交該刪除操作後,兩個會話看到的才是一致的資料。

鎖的概念
鎖出現在資料共享的場合,用來保證資料的一致性。當多個會話同時修改一個表時,需要對資料進行相應的鎖定。
鎖有“只讀鎖”、“排它鎖”,“共享排它鎖”等多種型別,而且每種型別又有“行級鎖”(一次鎖住一條記錄),“頁級鎖”(一次鎖住一頁,即資料庫中儲存記錄的最小可分配單元),“表級鎖”(鎖住整個表)。

排它鎖和共享鎖

排它鎖又稱為寫鎖((Exclusive lock,簡記為X鎖)),若事務T對資料物件A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何型別的鎖,直到T釋放A上的鎖。它防止任何其它事務獲取資源上的鎖,直到在事務的末尾將資源上的原始鎖釋放為止。在更新操作(INSERT、UPDATE 或 DELETE)過程中始終應用排它鎖。
     共享鎖又稱為讀鎖(Share lock,簡記為S鎖),若事務T對資料物件A加上S鎖,則其它事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。
     共享鎖:由非更新(讀取)操作建立的鎖。其他使用者可以併發讀取資料,但任何事務都不能獲取資料上的排它鎖,直到已釋放所有共享鎖。 

若為“行級排它鎖”,則除被鎖住的行外,該表中其他行均可被其他的使用者進行修改(Update)或刪除(delete)。若為“表級排它鎖”,則所有其他使用者只能對該表進行查詢(select)操作,而無法對其中的任何記錄進行修改或刪除。當程式對所做的修改進行提交(commit)或回滾(rollback)後,鎖住的資源便會得到釋放,從而允許其他使用者進行操作。
有時,由於程式的原因,鎖住資源後長時間未對其工作進行提交;或是由於使用者的原因,調出需要修改的資料後,未及時修改並提交,而是放置於一旁;或是由於客戶伺服器方式中客戶端出現“宕機”,而伺服器端卻並未檢測到,從而造成鎖定的資源未被及時釋放,影響到其他使用者的操作。
如果兩個事務,分別鎖定一部分資料,而都在等待對方釋放鎖才能完成事務操作,這種情況下就會發生死鎖。

隱式鎖和顯式鎖
在Oracle資料庫中,修改資料操作時需要一個隱式的獨佔鎖,以鎖定修改的行,直到修改被提交或撤銷為止。如果一個會話鎖定了資料,那麼第二個會話要想對資料進行修改,只能等到第一個會話對修改使用COMMIT命令進行提交或使用ROLLBACK命令進行回滾撤銷後,才開始執行。因此應養成一個良好的習慣:執行修改操作後,要儘早地提交或撤銷,以免影響其他會話對資料的修改。

對emp表的SCOTT僱員記錄進行修改,測試隱式鎖
步驟1:啟動第一個SQL*Plus,以SCOTT賬戶登入資料庫(第一個會話),修改SCOTT記錄,隱式加鎖。
Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=3500 where empno=7788;  

執行結果:
已更新 1 行。
步驟2:啟動第二個SQL*Plus,以SCOTT賬戶登入資料庫(第二個會話),進行記錄修改操作。
Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=4000 where empno=7788;  

執行結果,沒有任何輸出(處於等待解鎖狀態)。

步驟3:對第一個會話進行解鎖操作:
Sql程式碼  收藏程式碼
  1. COMMIT;  

步驟4:檢視第二個會話,此時有輸出結果:
已更新 1 行。
步驟5:提交第二個會話,防止長時間鎖定。
說明:兩個會話對同一表的同一條記錄進行修改。步驟1修改SCOTT工資為3500,沒有提交或回滾之前,SCOTT記錄處於加鎖狀態。步驟2的第二個會話對SCOTT進行修改處於等待狀態。
步驟3解鎖之後(即第一個會話對SCOTT的修改已經完成),第二個會話掛起的修改此時可以執行。最後結果為第二個會話的修改結果,即SCOTT的工資修改為4000。讀者可以使用查詢語句檢查。
以上是隱式加鎖,使用者也可以使用如下兩種方式主動鎖定行或表,防止其他會話對資料的修改。

SELECT FOR UPDATE:鎖定錶行,防止其他會話對行的修改
LOCK TABLE:鎖定表,防止其他會話對錶的修改

對emp表的部門10的僱員記錄加顯式鎖,並測試。
步驟1:對部門10加顯式鎖:
Sql程式碼  收藏程式碼
  1. SELECT empno,ename,job,sal FROM emp WHERE deptno=10 FORUPDATE;  

結果為:
     Sql程式碼  收藏程式碼
  1. EMPNO ENAME     JOB                 SAL  
  2.         ------------------ -------------- ------------------ ------------------
  3.         7782  CLARK     MANAGER         2450  
  4.         7839  KING          PRESIDENT           5000  
  5.         7934  MILLER    CLERK               1300  

步驟2:啟動第二個SQL*Plus(第二個會話),以SCOTT賬戶登入資料庫,對部門10的僱員CLARK進行修改操作。
Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=sal+100 where empno=7782;  

執行結果:
沒有任何輸出(處於等待解鎖狀態)。
步驟3:在第一個會話進行解鎖操作:
Sql程式碼  收藏程式碼
  1. COMMIT;  

步驟4:檢視第二個會話,有輸出結果:
已更新 1 行。
說明:步驟1對選定的部門10的僱員加鎖,之後其他會話不能對部門10的僱員資料進行修改或刪除。如果此時要進行修改或刪除,則會處於等待狀態。使用COMMIT語句進行解鎖之後,如果有掛起的修改或刪除操作,則等待的操作此時可以執行。
鎖定表
LOCK語句用於對整張表進行鎖定。語法如下:
LOCK TABLE 表名 IN {SHARE|EXCLUSIVE} MODE
對錶的鎖定可以是共享(SHARE)或獨佔(EXCLUSIVE)模式。共享模式下,其他會話可以加共享鎖,但不能加獨佔鎖。在獨佔模式下,其他會話不能加共享或獨佔鎖。
【訓練1】  對emp表新增獨佔鎖。
步驟1:對emp表加獨佔鎖:
Sql程式碼  收藏程式碼
  1. LOCK TABLE emp IN EXCLUSIVE MODE;  

結果為:
表已鎖定。

步驟2:對錶進行解鎖操作:
Sql程式碼  收藏程式碼
  1. COMMIT;  

說明:當使用LOCK語句顯式鎖定一張表時,死鎖的概率就會增加。同樣地,使用COMMIT或ROLLBACK命令可以釋放鎖。
   注意:必須沒有其他會話對該表的任何記錄加鎖,此操作才能成功。

黑色頭髮:http://heisetoufa.iteye.com/