在任何多用戶數據庫應用中,最終必然會出現兩個用戶希望同時處理相同記錄的情況.這種情況在邏輯上是不可能的,并且數據庫必須確保其在物理上也是不可能的.事務隔離性原則要求數據庫保證:在 ,這個會話無法影響另一個會話,并且后者也無法看到前者.為了實現這個要求,數據庫創行話并發的數據訪問,甚至在多個會話請求訪問相同的記錄時,數據庫也必須確保這些會話排隊依次進行.
借助于記錄和表鎖定機制,我們可以實現并發的串行化.oracle數據庫中的鎖定是完全自動的.一般而言,只有在試圖結合軟件與自動鎖定機制是或者編程人員編寫的代碼太糟糕時才會引發某些問題.
共享鎖與排他鎖
Oracle數據庫中鎖定的標準級別保證了最大可能的并發級別也就是說,如果某個會話正在更新一條記錄,那么只有這條記錄會被鎖定.此外,鎖定這條記錄是為了防止其他會話對其進行更新,其他會話可以隨時執行讀取操作.只有在使用commit或rollback命令結束事務之后,鎖定才會被解除.這種鎖定是一個”排他鎖”:在指定記錄上請求排他鎖的第一個會話會得到這個鎖定,其他請求對該記錄進行寫訪問的會話則必須等待.雖然這條記錄已通過鎖定會話進行了更新,但是對其進行讀訪問你是被允許的(而且經常會出現這種情況),并且這些讀操作會涉及撤銷數據的使用,從而確保都會回并不會看到任何未被提交的變化對于一條記錄或一個完整表上的一個排他鎖來說,每次只能有一個會話可以獲得這個排他鎖,不過許多會話可以同時獲得相同對象上的”共享鎖”.在一條記錄上設置共享鎖毫無意義,其原因在于鎖定一條記錄的唯一目的就是不允許其他會話更改它.共享鎖被置于整個表上,同時許多會話可以獲得同一個表上的共享鎖.在一個表上放置共享鎖的目的是為了防止另一個會話獲得這個表上的排他鎖(在已存在共享鎖的情況下無法再獲得排他鎖).在表上防止排他鎖是需要執行DDL語句.如果其他任何會話已經在一個表上放置了共享鎖,那么我們就無法執行修改某個對象的語句(例如刪除這個表的某一列).
為了在記錄上執行DML語句,當前會話必須獲取待更新記錄上的排他鎖以及包含這些記錄的表上的共享鎖.如果另一個會話已經獲取了待更新記錄上的排他鎖,那么當前會話將被掛起,直至使用COMMIT或ROLLBACK命令解除這些鎖定,如果另一個會話已經獲取了待修改記錄的表上的共享鎖以及其他記錄上的排他鎖,那么就不存在任何問題.一個表上的排他鎖會鎖定這個表,但是,如果不需要執行DDL語句,那么我們就可以不鎖定整個表的默認鎖定機制.
提示:只有在特別請求并且編程人員具有充分理由的情況下,才可以要求在整個表上放置排他鎖.
DML鎖與DDL鎖
所有DML語句都至少需要兩種鎖定:受影響記錄上的排他鎖,以及包含受影響記錄的表上的共享鎖.排他鎖能夠防止其他會話干預指定的記錄,而共享鎖則能夠阻止其他會話使用DDL語句修改表的定義.這兩種鎖定會被自動請求.如果某條DML語句在指定記錄上無法獲取所需的排他鎖,那么這條語句會被掛起直至獲得所需的排他鎖.
執行DDL命令需要使用所涉及對象上的排他鎖.只有在針對指定表的所有DML事務結束,并且記錄上的排他鎖以及表上的共享鎖都被解除之后,我們才可以獲得執行DDL命令所需的排他鎖,任何DDL語句所需的排他鎖都是被自動請求的.但是,如果無法獲取所需的排他鎖(通常是因為其他會話已經獲得用于DML語句的共享鎖),那么DDL語句就會由于錯誤立即終止.
例子:
1. 使用SQL*PLUS,作為用戶SYSTEM連接數據庫.
2. 創建一個表,并且在這個表中插入一條記錄.
>create table t1(c1 number);
>insert into t1 values(1);
>commit;
3.再次使用SQL*PLUS并作為用戶SYSTEM進行連接,從而打開另一個會話.
4.在第一個會話中執行一個DML命令,這個命令會在插入的記錄上放置一個排他鎖,同時還會在創建的表上放置一個共享鎖.
>update table t1 set c1=2 where c1=1;
5.如下所示,在第二個會話中執行第一條針對新建表的DDL語句.
>alter table t1 add(c2 date);
error at line 1:
ora-00054:resource busy and acquire with nowait specified
因為DDL語句需要表上的排他鎖,而這與DML語句已在表上放置了共享鎖相沖突,所以試圖在表中插入一個列的這條DDL語句會失敗.需要注意的是:在類似情況下,DML語句會等待并不斷進行嘗試,直至獲得其所需的鎖(換句話說就是掛起);而DDL語句則會由于錯誤立即終止.
6.在第一個會話中,提交當前事務
>commit;
7.在第二個會話中,重新執行步驟5.此時,因為不純在與DDL排他鎖相沖突的DML共享鎖,因此DDL語句將成功的執行.
8.在第一個會話中 ,鎖定整個表.
>lock table t1 in exclusive mode;
9.在第二個會話中,插入一條記錄.此時,這個會話將被掛起.
>insert into t1 values (1,sysdate);
10.在第一個會話中,通過執行COMMIT命令解除整個表上的鎖定.需要注意的是,ROLLBACK命令也可以實現相同的目的.
>commit;
11.第二個會話會釋放并且現在會完成插入操作.隨后,執行COMMIT命令,終止當前事務斌且解除該記錄上的排他鎖.
關于如何解決死鎖的問題.
1.查哪個過程被鎖
查V$DB_OBJECT_CACHE視圖:
SELECT * FROM V$DB_OBJECT_CACHE WHERE OWNER=''過程的所屬用戶'' AND LOCKS!=''0'';
2. 查是哪一個SID,通過SID可知道是哪個SESSION.
查V$ACCESS視圖:
SELECT * FROM V$ACCESS WHERE OWNER=''過程的所屬用戶'' AND NAME=''剛才查到的過程名
版權歸原作者和各發布網站所有,此文章僅供學習參考之用
天天學習,好好向上——
posted on 2008-11-07 15:40
東頭bing阿頭 閱讀(4075)
評論(1) 編輯 收藏 所屬分類:
DataBase