【鎖】Oracle鎖系列javascript
各位技術愛好者,看完本文後,你能夠掌握以下的技能,也能夠學到一些其它你所不知道的知識,~O(∩_∩)O~:html
① 鎖的概念、分類、及其模擬java
② 查詢鎖的視圖及視圖之間的關聯sql
③ 鎖的參數(DML_LOCKS、DDL_LOCK_TIMEOUT)數據庫
④ FOR UPDATE及FOR UPDATE OF系列緩存
⑤ 帶ONLINE和不帶ONLINE建立索引的鎖狀況(是否阻塞DML操做)安全
⑥ 包或存過不能編譯的解決方法服務器
⑦ ORA-08104解決方法微信
Tips:網絡
① 本文在itpub(http://blog.itpub.net/26736162)、博客園(http://www.cnblogs.com/lhrbest)和微信公衆號(xiaomaimiaolhr)上有同步更新。
② 文章中用到的全部代碼、相關軟件、相關資料及本文的pdf版本都請前往小麥苗的雲盤下載,小麥苗的雲盤地址見:http://blog.itpub.net/26736162/viewspace-1624453/。
③ 若網頁文章代碼格式有錯亂,請下載pdf格式的文檔來閱讀。
④ 在本篇BLOG中,代碼輸出部分通常放在一行一列的表格中。其中,須要特別關注的地方我都用灰色背景和粉紅色字體來表示,好比在下邊的例子中,thread 1的最大歸檔日誌號爲33,thread 2的最大歸檔日誌號爲43是須要特別關注的地方;而命令通常使用黃色背景和紅色字體標註;對代碼或代碼輸出部分的註釋通常採用藍色字體表示。
List of Archived Logs in backup set 11 Thrd Seq Low SCN Low Time Next SCN Next Time ---- ------- ---------- ------------------- ---------- --------- 1 32 1621589 2015-05-29 11:09:52 1625242 2015-05-29 11:15:48 1 33 1625242 2015-05-29 11:15:48 1625293 2015-05-29 11:15:58 2 42 1613951 2015-05-29 10:41:18 1625245 2015-05-29 11:15:49 2 43 1625245 2015-05-29 11:15:49 1625253 2015-05-29 11:15:53 [ZHLHRDB1:root]:/>lsvg -o T_XLHRD_APP1_vg rootvg [ZHLHRDB1:root]:/> 00:27:22 SQL> alter tablespace idxtbs read write; ====》2097152*512/1024/1024/1024=1G |
本文若有錯誤或不完善的地方請你們多多指正,ITPUB留言或QQ皆可,您的批評指正是我寫做的最大動力。
有網友一直催着說發一些鎖系列的文章,其實小麥苗一直對鎖這塊也沒有完全去研究過,今年寫書裏邊寫到了鎖的內容,乾脆就完全把這一塊整理了一下,如今分享給你們,如有錯誤,還請你們及時指正。
文章不少內容來源於網絡或Concepts的內容,如有侵權還請聯繫小麥苗刪除。
鎖的定義:鎖(lock)機制用於管理對共享資源的併發訪問,用於多用戶的環境下,能夠保證數據庫的完整性和一致性。鎖是防止訪問相同資源的事務之間的破壞性交互的機制。既能夠是用戶對象(例如表或行),也能夠是對用戶不可見的系統對象(例如共享數據結構和數據字典行)。
鎖的解釋:當多個用戶併發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的狀況。若對併發操做不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的完整性和一致性。當事務在對某個數據對象進行操做前,先向系統發出請求,對其加鎖。加鎖後事務就對該數據對象有了必定的控制。
鎖的做用:在併發事務之間防止破壞性的交互做用,不須要用戶的動做,自動使用最低的限制級別,在事務處理期間保持。
數據庫是一個多用戶使用的共享資源。當多個用戶併發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的狀況。若對併發操做不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性。
鎖(lock)是防止訪問相同資源(例如表或數據行等用戶對象,或內存中的共享數據結構及數據字典等對用戶不可見的系統對象)的事務產生破壞性交互的機制。
在任何狀況下,Oracle 都可以自動地得到執行 SQL 語句所必須的全部鎖,無需用戶干預。Oracle 會盡量地減小鎖產生的影響,從而最大程度地保證數據的併發訪問能力,並確保數據一致性及錯誤恢復。同時,Oracle 也支持用戶手工加鎖的操做。
Oracle 歷來不會升級鎖,可是它會執行鎖轉換(lock conversion)或鎖提高(lock promotion)。
A lock is a mechanism that prevents destructive interactions, which are interactions that incorrectly update data or incorrectly alter underlying data structures, between transactions accessing shared data. Locks play a crucial row in maintaining database concurrency and consistency.
鎖是一種機制,用來防止多個共同訪問共享數據的事務之間的破壞性交互,包括不正確地更新數據或不正確地更改基礎數據結構。鎖在維護數據庫併發性和一致性當中扮演着一個關鍵的角色。
併發(concurrency)和並行(parallel)。併發意思是在數據庫中有超過兩個以上用戶對一樣的數據作修改,而並行的意思就是將一個任務分紅不少小的任務,讓每個小任務同時執行,最後將結果彙總到一塊兒。因此說,鎖產生的緣由就是併發,併發產生的緣由是由於系統和客戶的須要。
在單用戶數據庫中,鎖不是必需的,由於只有一個用戶在修改信息。可是,當多個用戶在訪問和修改數據時,數據庫必須提供一種方法,以防止對同一數據進行併發修改。鎖實現瞭如下重要的數據庫需求:
v ·一致性
一個會話正在查看或更改的數據不能被其它會話更改,直到用戶會話結束。
v ·完整性
數據和結構必須按正確的順序反映對他們所作的全部更改。數據庫經過其鎖定機制,提供在多個事務之間的數據併發性、一致性、和完整性。鎖定將自動執行,而且不須要用戶操做。
執行SQL語句時,Oracle數據庫自動獲取所需的鎖。例如,在數據庫容許某個會話修改數據以前,該會話必須先鎖定數據。鎖給予該會話對數據的獨佔控制權,以便在釋放該鎖以前,任何其它事務都不能夠修改被鎖定的數據。
由於數據庫的鎖定機制與事務控制緊密地綁定在一塊兒,應用程序設計人員只須要正確地定義事務,而數據庫會自動管理鎖定。
Oracle數據庫自動使用最低適用的限制級別,來提供最高程度的數據併發,但還能提供很是安全的數據完整性。限制級別越低、則有更多的可用數據供其餘用戶訪問。相反,限制級別越高,則其它事務爲獲取其所需的鎖類型就將遭受更多的限制。
在多用戶的數據庫系統中,Oracle使用兩種模式的鎖:
事務內各語句得到的鎖在事務執行期內有效,以防止事務間破壞性的相互干擾,例如:髒讀取(dirty read),無效地更新(lost update),以及其它併發事務中具備破壞性的 DDL 操做。若是某個事務中的 SQL 語句對數據進行了修改,只有在此事務提交後開始的事務才能看到前者修改的結果。
當用戶提交(commit)或撤銷(undo)一個事務後,Oracle 將釋放此事務內各個 SQL 語句得到的鎖。當用戶在事務內回滾到某個保存點(savepoint)後,Oracle 也會釋放此保存點後得到的鎖。只有當前沒有等待被鎖資源的事務才能得到可用資源的鎖。等待事務不會對可用資源加鎖而是繼續等待,直至擁有其所等待資源的事務完成提交或回滾。
有兩種類型:顯式鎖定和隱式鎖定。Oracle鎖被自動執行,而且不要求用戶干預的鎖爲隱式鎖。對於SQL語句隱式鎖是必須的,依賴被請求的動做。隱式鎖定除SELECT外,對全部的SQL語句都發生。用戶也能夠手動鎖定數據,這是顯式鎖定。
隱式鎖定:這是Oracle中使用最多的鎖。一般用戶沒必要聲明要對誰加鎖,Oracle 自動能夠爲操做的對象加鎖,這就是隱式鎖定。
顯式鎖定:用戶可使用命令明確的要求對某一對象加鎖。顯式鎖定不多使用。
LOCK TABLE沒有觸發行鎖,只有TM表鎖。
LOCK TABLE TABLE_NAME IN ROW SHARE MODE NOWAIT; --2:RS LOCK TABLE TABLE_NAME IN SHARE UPDATE MODE; --2:RS LOCK TABLE TABLE_NAME IN ROW EXCLUSIVE MODE NOWAIT; --3:RX LOCK TABLE TABLE_NAME IN SHARE MODE; --4:S LOCK TABLE TABLE_NAME IN SHARE ROW EXCLUSIVE MODE; --5:SRX LOCK TABLE TABLE_NAME IN EXCLUSIVE MODE NOWAIT; --6:X |
隱式鎖定:
Select * from table_name……
Insert into table_name……
Update table_name……
Delete from table_name……
Select * from table_name for update
鎖在用戶修改以前就發揮做用:
Select ..for update(nowait)
Select * from tab1 for update
用戶發出這條命令以後,oracle將會對返回集中的數據創建行級封鎖,以防止其餘用戶的修改。
若是此時其餘用戶對上面返回結果集的數據進行dml或ddl操做都會返回一個錯誤信息或發生阻塞。
1:對返回結果集進行update或delete操做會發生阻塞。
2:對該表進行ddl操做將會報:Ora-00054:resource busy and acquire with nowait specified.
緣由分析
此時Oracle已經對返回的結果集上加了排它的行級鎖,全部其餘對這些數據進行的修改或刪除操做都必須等待這個鎖的釋放,產生的外在現象就是其它的操做將發生阻塞,這個這個操做commit或rollback.
一樣這個查詢的事務將會對該表加表級鎖,不容許對該表的任何ddl操做,不然將會報出ora-00054錯誤::resource busy and acquire with nowait specified.
會話1:
SYS@lhrdb S1> create table t_lock_lhr as select rownum as id,0 as type from dual connect by rownum <=3;
Table created.
SYS@lhrdb S1> select * from t_lock_lhr where id=2 and type =0 for update nowait;
ID TYPE ---------- ---------- 2 0 |
會話2:
SYS@lhrdb S2> select * from t_lock_lhr where id=2 and type=0 for update nowait; select * from t_lock_lhr where id=2 and type=0 for update nowait * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
|
會話1:
SYS@lhrdb S1> update t_lock_lhr set type=1 where id=2 and type=0;
1 row updated.
SYS@lhrdb S1> commit;
Commit complete.
SYS@lhrdb S1> select * from t_lock_lhr where id=2;
ID TYPE ---------- ---------- 2 1
|
會話2:
SYS@lhrdb S2> select * from t_lock_lhr where id=2 and type=0 for update nowait;
no rows selected
|
樂觀的認爲數據在select出來到update進取並提交的這段時間數據不會被更改。這裏面有一種潛在的危險就是因爲被選出的結果集並無被鎖定,是存在一種可能被其餘用戶更改的可能。所以Oracle仍然建議是用悲觀封鎖,由於這樣會更安全。
會話1: SYS@lhrdb S1> select id,type,ora_rowscn from t_lock_lhr where id = 3;
ID TYPE ORA_ROWSCN ---------- ---------- ---------- 3 0 37698547 會話2: SYS@lhrdb S2> select id,type,ora_rowscn from t_lock_lhr where id = 3;
ID TYPE ORA_ROWSCN ---------- ---------- ---------- 3 0 37698547 會話1: SYS@lhrdb S1> update t_lock_lhr set type=1 where ora_rowscn=37698547 and id = 3;
1 row updated.
SYS@lhrdb S1> commit;
Commit complete. SYS@lhrdb S1> select id,type,ora_rowscn from t_lock_lhr where id = 3;
ID TYPE ORA_ROWSCN ---------- ---------- ---------- 3 1 37698591 會話2: SYS@lhrdb S2> update t_lock_lhr set type=1 where ora_rowscn=37698547 and id =3;
0 rows updated.
SYS@lhrdb S2> select id,type,ora_rowscn from t_lock_lhr where id = 3;
ID TYPE ORA_ROWSCN ---------- ---------- ---------- 3 1 37698591
|
更新丟失是指多個用戶經過應用程序訪問數據庫時,因爲查詢數據並返回到頁面和用戶修改完畢點擊保存按鈕將修改後的結果保存到數據庫這個時間段(即修改數據在頁面上停留的時間)在不一樣用戶之間可能存在誤差,從而最早查詢數據而且最後提交數據的用戶會把其餘用戶所做的修改覆蓋掉。
解決方法以下:
數據庫在必要時執行鎖轉換。在鎖轉換中,數據庫自動將較低限制的表鎖轉換爲較高限制的其它鎖定。一個事務在該事務中全部執行插入、更新、或刪除的行上持有行獨佔鎖。由於行鎖是在最高程度限制下得到的,所以不要求鎖轉換,也不執行鎖轉換。鎖轉換不一樣於鎖升級,鎖升級發生在當某個粒度級別持有許多鎖(例如行),數據庫將其提升到更高粒度級別(例如表)。若是一個用戶鎖定了一個表中的許多行,則某些數據庫自動將行鎖升級到單個表鎖。鎖的數量減小了,但被鎖定的東西卻增長了。
Oracle數據庫永遠不會升級鎖。鎖升級極大地增長了死鎖的可能性。假定一個系統嘗試升級事務1中的鎖,但由於事務2持有該鎖,故不能成功。若是事務2在它能夠繼續操做以前也須要在相同的數據上進行鎖升級,則將發生一個死鎖。
ORACLE的鎖是block裏面實現的,SQLSERVER,DB2是內存裏面實現的.內存實現有資源消耗問題,當內存不足會引起鎖升級,可是ORACLE不會發生鎖升級。
事務擁有在此事務內被插入(insert),更新(update),刪除(delete)的數據行的排它行級鎖(exclusive row lock)。對於數據行來講,排它行級鎖已是限制程度最高的鎖,所以無需再進行鎖轉換(lock conversion)。
Oracle可以自動地選擇不一樣類型的鎖對數據併發訪問進行控制,防止用戶間破壞性的交互操做。Oracle 將自動地爲事務進行鎖管理,防止其它事務對須要排它訪問的資源執行操做。當事務再也不須要加鎖的資源並觸發某個事件後,鎖可以被自動地釋放。
在事務執行期間,Oracle 可以根據加鎖的資源及須要執行的操做自動地決定鎖的類型(types of lock)及對資源的限制級別(level of restrictiveness)。
V$LOCK_TYPE 該視圖是對DML鎖的類型的解釋。
select * from V$LOCK_TYPE v where v.IS_USER='YES';
當Oracle執行DML語句時,系統自動在所要操做的表上申請TM類型的鎖。當TM鎖得到後,系統再自動申請TX類型的鎖,並將實際鎖定的數據行的鎖標誌位進行置位。這樣在事務加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標誌,而只需檢查TM鎖模式的相容性便可,大大提升了系統的效率。TM鎖包括了SS、SX、S、X等多種模式,在數據庫中用0-6來表示。不一樣的SQL操做產生不一樣類型的TM鎖。
在數據行上只有X鎖(排它鎖)。在Oracle數據庫中,當一個事務首次發起一個DML語句時就得到一個TX鎖,該鎖保持到事務被提交或回滾。當兩個或多個會話在表的同一條記錄上執行DML語句時,第一個會話在該條記錄上加鎖,其它的會話處於等待狀態。當第一個會話提交後,TX鎖被釋放,其它會話才能夠加鎖。
當Oracle數據庫發生TX鎖等待時,若是不及時處理經常會引發Oracle數據庫掛起,或致使死鎖的發生,產生ORA-60的錯誤。這些現象都會對實際應用產生極大的危害,如長時間未響應,大量事務失敗等。
當Oracle執行DELETE,UPDATE,INSERT,SELECT FOR UPDATE DML語句時,oracle首先自動在所要操做的表上申請TM類型的鎖。當TM鎖得到後,再自動申請TX類型的鎖,並將實際鎖定的數據行的鎖標誌位(lb 即lock bytes)進行置位。在記錄被某一會話鎖定後,其它須要訪問被鎖定對象的會話會按先進先出的方式等待鎖的釋放,對於select操做而言,並不須要任何鎖,因此即便記錄被鎖定,select語句依然能夠執行,實際上,在此狀況下,oracle是用到undo的內容進行一致性讀來實現的。
當Oracle執行DML語句時,系統自動在所要操做的表上申請TM類型的鎖。當TM鎖得到後,系統再自動申請TX類型的鎖,並將實際鎖定的數據行的鎖標誌位進行置位。這樣在事務加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標誌,而只需檢查TM鎖模式的相容性便可,大大提升了系統的效率。DML語句可以自動地得到所需的表級鎖(table-level lock)與行級鎖(row-level lock)。
DML鎖,也稱爲數據鎖,確保由多個用戶併發訪問的數據的完整性。例如,DML鎖可防止兩個客戶從一個在線書店購買某一本書所剩的最後一個拷貝。DML鎖也能夠防止多個相互衝突的DML或DDL操做產生破壞性干擾。
DML語句自動獲取下列類型的鎖:
n 行鎖(TX)
n 表鎖(TM)
行級鎖(row-level lock)的做用是防止兩個事務同時修改相同的數據行。當一個事務須要修改一行數據時,就需對此行數據加鎖。Oracle 對語句或事務所能得到的行級鎖的數量沒有限制,Oracle 也不會講行級鎖的粒度升級(lock escalation)。行級鎖是粒度最精細的鎖,所以行級鎖可以提供最好的數據併發訪問能力及數據處理能力。
Oracle 同時支持多版本併發訪問控制(multiversion concurrency control)及行級鎖技術(row-level locking),所以用戶只有在訪問相同數據行時纔會出現競爭,具體來講:
l 讀取操做無需等待對相同數據行的寫入操做。
l 寫入操做無需等待對相同數據行的讀取操做,除非讀取操做使用了 SELECT ... FOR UPDATE 語句,此讀取語句須要對數據加鎖。
l 寫入操做只需等待併發地且針對相同數據行的其它寫入操做。
提示:讀取操做可能會等待對相同數據塊(data block)的寫入操做,這種狀況只會在出現掛起的分佈式事務(pending distributed transaction)時偶爾出現。
在執行下列語句時,事務須要得到被修改的每一數據行的排它行級鎖(exclusive row lock):INSERT,UPDATE,DELETE,及使用了FOR UPDATE 子句的 SELECT 語句。
在事務被提交或回滾前,此事務擁有在其內部被修改的全部數據行的排它鎖,其它事務不能對這些數據行進行修改操做。可是,若是事務因爲實例故障而終止,在整個事務被恢復前,數據塊級的恢復將使數據塊內數據行上的鎖釋放。執行前面提到的 4 種 SQL 語句時,Oracle 能自動地對行級鎖進行管理。
當事務得到了某些數據行上的行級鎖時,此事務同時得到了數據行所屬表上的表級鎖(table lock)。表級鎖可以防止系統中併發地執行有衝突的 DDL 操做,避免當前事務中的數據操做被併發地 DDL 操做影響。
行級鎖機制:
當一個事務開始時,必須申請一個TX鎖,這種鎖保護的資源是回滾段、回滾數據塊。所以申請也就意味着:用戶進程必須先申請到回滾段資源後纔開始一個事務,才能執行DML操做。申請到回滾段後,用戶事務就能夠修改數據了。具體順序以下:
一、首先得到TM鎖,保護事務執行時,其餘用戶不能修改表結構
二、事務修改某個數據塊中記錄時,該數據塊頭部的ITL表中申請一個空閒表項,在其中記錄事務項號,實際就是記錄這個事務要使用的回滾段的地址(應該叫包含)
三、事務修改數據塊中的某條記錄時,會設置記錄頭部的ITL索引指向上一步申請到的表項。而後修改記錄。修改前先在回滾段將記錄以前的狀態作一個拷貝,而後修改表中數據。
四、其餘用戶併發修改這條記錄時,會根據記錄頭部ITL索引讀取ITL表項內容,確認是否事務提交。
五、若沒有提交,必須等待TX鎖釋放
從上面的機制來看,不管一個事務修改多少條記錄,都只須要一個TX鎖。所謂的「行級鎖」其實也就是數據塊頭、數據記錄頭的一些字段,不會消耗額外的資源。 從另外一方面也證實了,當用戶被阻塞時,不是被某條記錄阻塞,而是被TX鎖堵塞。也正由於這點,不少人也傾向把TX鎖稱爲事務鎖。這裏可經過實驗來驗證所說 結論。
會話1:
SQL> select * from test; ID NAME ---------- -------- 1 A 2 B 3 C
SQL> savepoint a; Savepoint created.
SQL> update test set name='ssss' where id=2; 1 row updated.
|
會話2,更新同一行發生阻塞:
SQL> update test set name='ssdsdsds'where id=2;
|
會話1:
SQL> rollback to a; Rollback complete.
|
能夠看到,雖然會話1已經撤銷了對記錄的修改,可是會話2仍然處於等待狀態這是由於會話2是被會話1的TX鎖阻塞的,而不是被會話1上的行級鎖 阻塞(rollback to savepoint不會結束事務) 。
會話3: SQL> select username,event,sid,blocking_session from v$session where SID IN (146,159); USERNAME EVENT SID BLOCKING_SESSION -------- ----------------------------------- ---------- ---------------- HR enq: TX - row lock contention 146 159 HR SQL*Net message from client 159 會話1: SQL> rollback; 會話2: SQL> update test set name='ssdsdsds'where id=2; 1 row updated. 會話3: SQL> select username,event,sid,blocking_session from v$session where username='HR'; USERNAME EVENT SID BLOCKING_SESSION -------- ----------------------------------- ---------- ---------------- HR SQL*Net message from client 159 |
事務結束,tx鎖釋放,會話2update執行成功。
行鎖,也稱爲TX 鎖,是一個表中單個行上的鎖。一個事務在被INSERT、UPDATE、DELETE、MERGE、或SELECT ... FOR UPDATE 等語句所修改的每一行上獲取一個行鎖。行鎖一直存在直到事務提交或回滾。行鎖主要做爲一種排隊的機制,以防止兩個事務修改相同的行。數據庫始終以獨佔模式鎖定修改的行,以便其它事務不能修改該行,直到持有鎖的事務提交或回滾。行鎖定提供了近乎最細粒度的鎖定,並所以提供了近乎最佳的併發性和吞吐量。
若是一個事務由於數據庫實例失效而終止,會先進行塊級恢復以使行可用,以後進行整個事務恢復。
表級鎖(table-level lock)的做用是對併發的 DDL 操做進行訪問控制,例如防止在 DML 語句執行期間相關的表被移除。當用戶對錶執行 DDL 或 DML 操做時,將獲取一個此表的表級鎖。表級鎖不會影響其餘併發的 DML 操做。對於分區表來講,表級鎖既能夠針對整個表,也能夠只針對某個分區。
當用戶執行如下 DML 語句對錶進行修改:INSERT,UPDATE,DELETE,及 SELECT ... FOR UPDATE,或執行 LOCK TABLE 語句時,事務將獲取一個表級鎖。這些 DML 語句獲取表級鎖的目的有兩個:首先保證自身對錶的訪問不受其它事務 DML 語句的干擾,其次阻止其它事務中和自身有衝突的 DDL 操做執行。任何類型的表級鎖都將阻止對此表的排它 DDL 鎖(exclusive DDL lock),從而阻止了必須具有排它 DDL 鎖才能執行的 DDL 操做。例如,當一個未提交的事務擁有某個表上的鎖時,此表就沒法被修改定義或被移除。
表級鎖具備如下幾種模式:行共享(row share,RS),行排它(row exclusive,RX),共享(share,S),共享行排它(share row exclusive,SRX),及排它(exclusive,X)。各類模式的表級鎖具備的限制級別決定了其是否能與其餘表級鎖共處於同一數據表上。
下表顯示了各類語句所得到的表級鎖的模式,以及此模式下被容許或禁止的操做。
ORACLE裏鎖有如下幾種模式:
鎖的兼容模式以下表所示:
表鎖,也稱爲TM鎖,當一個表被INSERT、UPDATE、DELETE、MERGE、帶FOR UPDATE子句的SELECT等修改時,由相關事務獲取該鎖。DML操做須要表鎖來爲事務保護DML對錶的訪問,並防止可能與事務衝突的DDL操做。
表鎖可能如下列模式之一持有:
這種鎖也被稱爲子共享表鎖(SS,subshare table lock),表示在表上持有鎖的事務在表中有被鎖定的行,並打算更新它們。行共享鎖是限制最少的表級鎖模式,提供在表上最高程度的併發性。
ROW SHARE模式容許同時訪問被鎖定的表,可是禁止用戶以排它方式鎖定整個表。ROW SHARE與SHARE UPDATE相同,只是爲了兼容早期的Oracle版本。對應lmode2,row-S (SS)。
版本:11.2.0.4
會話1: SYS@lhrdb> set sqlprompt "_user'@'_connect_identifier S1> " SYS@lhrdb S1> select userenv('sid') from dual;
USERENV('SID') -------------- 6
SYS@lhrdb S1> LOCK TABLE SCOTT.EMP IN ROW SHARE MODE;
Table(s) Locked. 會話2: SYS@lhrdb> set sqlprompt "_user'@'_connect_identifier S2> " SYS@lhrdb S2> select userenv('sid') from dual;
USERENV('SID') -------------- 114
SYS@lhrdb S2> LOCK TABLE SCOTT.EMP IN EXCLUSIVE MODE;
====>>>>> 產生了阻塞 查詢2個會話的鎖: SYS@lhrdb S1> SELECT D.SID, D.TYPE, D.ID1, D.ID2, D.LMODE, D.REQUEST, D.CTIME, D.BLOCK 2 FROM V$LOCK D 3 WHERE D.SID IN (114, 6) 4 ORDER BY D.SID, D.TYPE; SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 6 AE 100 0 4 0 231 0 6 TM 86893 0 2 0 169 1 114 AE 100 0 4 0 378 0 114 TM 86893 0 0 6 144 0 114 TO 79619 1 3 0 376 0 |
SELECT D.SID, D.TYPE, D.ID1, D.ID2, D.LMODE, D.REQUEST, D.CTIME, D.BLOCK
FROM V$LOCK D
WHERE D.SID IN (114, 6)
ORDER BY D.SID, D.TYPE;
由BLOCK列能夠看到sid爲6的會話阻塞了一個會話,這裏其實就是114,而114正在請求模式爲6的鎖。將2個會話提交後繼續測試:
SYS@lhrdb S1> LOCK TABLE SCOTT.EMP IN SHARE UPDATE MODE;
Table(s) Locked.
SYS@lhrdb S1> SELECT D.SID, D.TYPE, D.ID1, D.ID2, D.LMODE, D.REQUEST, D.CTIME, D.BLOCK 2 FROM V$LOCK D 3 WHERE D.SID IN (114, 6) 4 AND D.TYPE = 'TM' 5 ORDER BY D.SID, D.TYPE;
SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 6 TM 86893 0 2 0 387 0
|
這種鎖也被稱爲子獨佔表鎖(SX,subexclusive table lock),一般表示持有鎖的事務已更新了錶行或發出了SELECT...FOR UPDATE。一個SX鎖容許其它事務併發地查詢、插入、更新、刪除、或鎖定在同一個表中的其它行。所以,SX鎖容許多個事務對同一個表同時得到SX和子共享表鎖。
ROW EXCLUSIE相似於ROW SHARE模式,可是不能應用在SHARE模式中。當update,insert,delete發生時,ROW EXCLUSIVE會自動得到。對應lmode3,row-X (SX) 。
實驗內容:but it also prohibits locking in SHARE mode
會話1: SQL> set sqlprompt "_user'@'_connect_identifier S1> " SYS@oratest S1> select distinct sid from v$mystat;
SID ---------- 21 SYS@oratest S1> lock table scott.emp in share mode;
Table(s) Locked.
會話2: SQL> set sqlprompt "_user'@'_connect_identifier S2> " SYS@oratest S2> select distinct sid from v$mystat;
SID ---------- 142
SYS@oratest S2> lock table scott.emp in row exclusive mode;
====>>>>> 產生了阻塞
查看鎖: SYS@oratest S1> set line 9999 SYS@oratest S1> select * from v$lock where sid in (21,142);
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000000774D8518 00000000774D8570 142 TO 68064 1 3 0 7021 0 00000000774D9870 00000000774D98C8 142 TO 76985 1 3 0 7365 0 00000000774D9DC8 00000000774D9E20 21 AE 100 0 4 0 162 0 00000000774DA068 00000000774DA0C0 142 AE 100 0 4 0 7379 0 00007F567ADC2700 00007F567ADC2760 142 TM 75335 0 0 3 36 0 00007F567ADC2700 00007F567ADC2760 21 TM 75335 0 4 0 58 1
6 rows selected.
SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F567ADC7818 00007F567ADC7878 142 TM 75335 0 0 3 76 0 00007F567ADC7818 00007F567ADC7878 21 TM 75335 0 4 0 98 1
SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- ------------------------------ ------------------------------ ------------- ------------- ------------ ---------------------------------------- 142 SCOTT EMP None Row-X (SX) 101 Not Blocking 21 SCOTT EMP Share None 123 Blocking
SYS@oratest S1>
|
這裏能夠看到會話1的TM4阻塞了會話2的TM3。
提交2個會話後,接着實驗:ROW EXCLUSIVE locks are automatically obtained when updating, inserting, or deleting.
SYS@oratest S1> update scott.emp set sal=sal where empno=7369;
1 row updated.
SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F567ADE6AC8 00007F567ADE6B28 21 TM 75335 0 3 0 4 0 0000000076227AB0 0000000076227B28 21 TX 196620 1097 6 0 4 0
|
當會話1作了修改而沒有commit或者rollback時,這裏有兩個鎖,其中一個就是TM3的,一個是TX6的。
由某個事務擁有的共享表鎖容許其它事務查詢(而不使用SELECT...FOR UPDATE),可是更新操做只能在僅有單個事務持有共享表鎖時才容許。由於可能有多個事務同時持有共享表鎖,因此持有此鎖不足以確保一個事務能夠修改該表。
SHARE容許同時查詢,可是禁止更新被鎖定的表。對應lmode4,share (S) 。
會話1: SQL> set sqlprompt "_user'@'_connect_identifier S1> " SYS@oratest S1> select distinct sid from v$mystat;
SID ---------- 21 SYS@oratest S1> lock table scott.emp in share mode;
Table(s) Locked.
會話2: SQL> set sqlprompt "_user'@'_connect_identifier S2> " SYS@oratest S2> select distinct sid from v$mystat;
SID ---------- 142
SYS@oratest S2> update scott.emp set sal=sal where empno=7369;
====>>>>> 產生了阻塞
查看鎖: SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F567ADE6AC8 00007F567ADE6B28 142 TM 75335 0 0 3 43 0 00007F567ADE6AC8 00007F567ADE6B28 21 TM 75335 0 4 0 62 1
SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- -------- ------ ------------- ------------- ------------ --------------- 142 SCOTT EMP None Row-X (SX) 113 Not Blocking 21 SCOTT EMP Share None 132 Blocking SYS@oratest S1>
|
這裏能夠看到會話1的TM4阻塞了會話2的TM3。
這種鎖也稱爲共享子獨佔表鎖(SSX,share-subexclusive table lock),比共享表鎖的限制性更強。一次只能有一個事務能夠獲取給定的表上的SSX鎖。由某個事務擁有的SSX鎖容許其它事務查詢該表(除SELECT...FOR UPDATE)但不能更新該表。
共享行級排它鎖有時也稱共享子排它鎖(Share Subexclusive Table Lock,SSX),它比共享鎖有更多限制。定義共享行級排它鎖的語法爲:
Lock Table TableName In Share Row Exclusive Mode;
會話1: SQL> set sqlprompt "_user'@'_connect_identifier S1> " SYS@oratest S1> select distinct sid from v$mystat;
SID ---------- 21 SYS@oratest S1> lock table scott.emp in share row exclusive mode;
Table(s) Locked.
會話2: SQL> set sqlprompt "_user'@'_connect_identifier S2> " SYS@oratest S2> select distinct sid from v$mystat;
SID ---------- 142
SYS@oratest S2> lock table scott.emp in share mode;
====>>>>> 產生了阻塞
查看鎖: SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F567ADE7B00 00007F567ADE7B60 142 TM 75335 0 0 4 21 0 00007F567ADE7B00 00007F567ADE7B60 21 TM 75335 0 5 0 69 1 SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- ------- ------ ------------- ------------- ------------ --------------- 142 SCOTT EMP None Share 44 Not Blocking 21 SCOTT EMP S/Row-X (SSX) None 92 Blocking |
這裏能夠看到會話1的TM5阻塞了會話2的TM4。
這種鎖是最嚴格的鎖,禁止其它事務執行任何類型的DML語句,或在表上放置任何類型的鎖。
EXCLUSIVE EXCLUSIVE permits queries on the locked table but prohibits any other activity on it.
EXCLUSIVE模式容許查詢被鎖表上的數據,可是禁止任何其餘任何活動(這裏我理解是禁止添加其餘任何模式的鎖)。對應lomde6,exclusive (X) 。
會話1: SQL> set sqlprompt "_user'@'_connect_identifier S1> " SYS@oratest S1> select distinct sid from v$mystat;
SID ---------- 21 SYS@oratest S1> CREATE TABLE SCOTT.EMP_01 AS SELECT * FROM SCOTT.EMP;
Table created.
SYS@oratest S1> update scott.emp_01 set sal=sal where empno=7369;
1 row updated.
會話2: SQL> set sqlprompt "_user'@'_connect_identifier S2> " SYS@oratest S2> select distinct sid from v$mystat;
SID ---------- 142
SYS@oratest S2> DELETE FROM scott.emp_01 where empno=7369;
====>>>>> 產生了阻塞
查看鎖: SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000000774D9EA8 00000000774D9F00 142 TX 393247 1337 0 6 28 0 00007F567ABBC0A0 00007F567ABBC100 142 TM 77624 0 3 0 28 0 00007F567ABBC0A0 00007F567ABBC100 21 TM 77624 0 3 0 36 0 0000000076255548 00000000762555C0 21 TX 393247 1337 6 0 36 1
SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- -------- -------- ------------- ------------- ------------ --------------- 142 SCOTT EMP_01 Row-X (SX) None 35 Not Blocking 21 SCOTT EMP_01 Row-X (SX) None 43 Not Blocking |
在這裏,從BLOCK字段能夠看到會話1的TM3並沒堵塞會話2的TM3,這裏真正發生堵塞的是會話1的TX6。
這裏還有一個鎖定對象的問題。上面兩個TM3的鎖針對的對象是object_id爲77624的表,既然描述是相似行共享,天然是不會堵塞的。而兩個TX6的鎖針對的對象能夠理解成表中的行,在這些行上添加EXCLUSIVE鎖(lmode6,exclusive (X) )天然是會堵塞其餘的EXCLUSIVE鎖的。
解決這種類型的鎖堵塞固然就是在代碼中儘早commit結束事務。不少地方都寫到儘早commit能夠提升運行效率,這裏所指的是釋放鎖(特別是lmode6的EXCLUSIVE鎖)減小堵塞,以提升併發性。(不是以減小數據的量來提升效率的,事實上無論多大的數據量,一個commit的過程都是很"平"的。
會話1: SYS@lhrdb> set sqlprompt "_user'@'_connect_identifier S1> " SYS@lhrdb S1> SELECT DISTINCT SID FROM V$MYSTAT;
SID ---------- 27 SYS@lhrdb S1> CREATE TABLE T_APPEND_161107_LHR AS SELECT * FROM DUAL;
Table created.
SYS@lhrdb S1> INSERT /*+ APPEND */ INTO T_APPEND_161107_LHR SELECT * FROM DUAL;
3 rows created.
會話2: SYS@lhrdb> set sqlprompt "_user'@'_connect_identifier S2> " SYS@lhrdb S2> SELECT DISTINCT SID FROM V$MYSTAT;
SID ---------- 162
SYS@lhrdb S2> INSERT /*+ APPEND */ INTO T_APPEND_161107_LHR SELECT * FROM DUAL;
<<<<<<<<<-------- 產生了阻塞
|
會話3:
SYS@lhrdb> set sqlprompt "_user'@'_connect_identifier S3> " SYS@lhrdb S3> set line 9999 SYS@lhrdb S3> SELECT * FROM V$LOCK T WHERE T.SID IN (27,162) AND T.TYPE IN ('TX','TM') ORDER BY T.SID ;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000001109F5A40 00000001109F5AA0 27 TM 100957 0 6 0 2217 1 070001007C7EB2B0 070001007C7EB328 27 TX 589843 58249 6 0 2217 0 00000001109F5A40 00000001109F5AA0 162 TM 100957 0 0 6 2214 0
====>>>>> 過了好久 SYS@lhrdb S3> SELECT * FROM V$LOCK T WHERE T.SID IN (27,162) AND T.TYPE IN ('TX','TM') ORDER BY T.SID ;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000001109F6A78 00000001109F6AD8 27 TM 100957 0 6 0 2882 1 070001007C7EB2B0 070001007C7EB328 27 TX 589843 58249 6 0 2882 0 00000001109F6A78 00000001109F6AD8 162 TM 100957 0 0 6 2879 0
SYS@lhrdb S3> /
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000001109F5A40 00000001109F5AA0 27 TM 100957 0 6 0 2885 1 070001007C7EB2B0 070001007C7EB328 27 TX 589843 58249 6 0 2885 0 00000001109F5A40 00000001109F5AA0 162 TM 100957 0 0 6 2882 0
|
其中,會話1的sid爲27,分別在TX和TM級別,擁有LMODE爲6的X鎖。BLOCK爲1說明會話1阻塞了其它會話(0表示沒有阻塞,2表示RAC環境須要用GV$LOCK)。CTIME表示擁有此鎖的時間,單位爲秒。會話2的sid爲162,REQUEST爲6表示正在請求模式爲6的鎖。
當TYPE列爲TM的時候,即對於TM鎖來講,ID1列表示被鎖定的對象的對象ID,ID2始終爲0,以下:
SYS@lhrdb S3> COL OWNER FORMAT A5 SYS@lhrdb S3> COL OBJECT_NAME FORMAT A20 SYS@lhrdb S3> SELECT D.OWNER,D.OBJECT_NAME,D.OBJECT_ID FROM DBA_OBJECTS D WHERE D.OBJECT_ID = 100957; OWNER OBJECT_NAME OBJECT_ID ----- -------------------- ---------- SYS T_APPEND_161107_LHR 100957
|
當TYPE列爲TX的時候,即對於TX鎖來講,ID1列表示事務使用的回滾段編號以及在事務表中對應的記錄編號,ID2表示該記錄編號被重用的次數(wrap),ID1列表示事務的信息,以下:
SYS@lhrdb S3> SELECT A.TADDR FROM V$SESSION A WHERE SID = 27;
TADDR ---------------- 070001007C7EB2B0
SYS@lhrdb S3> SELECT A.XIDUSN, A.XIDSLOT, A.XIDSQN 2 FROM V$TRANSACTION A 3 WHERE A.ADDR = '070001007C7EB2B0';
XIDUSN XIDSLOT XIDSQN ---------- ---------- ---------- 9 19 58249
SYS@lhrdb S3> SELECT TRUNC(589843 / POWER(2, 16)) AS UNDO_SEG#, 2 BITAND(589843, TO_NUMBER('ffff', 'xxxx')) + 0 AS SLOT#, 3 58249 XIDSQN 4 FROM DUAL;
UNDO_SEG# SLOT# XIDSQN ---------- ---------- ---------- 9 19 58249
SYS@lhrdb S3> SELECT SID, 2 STATUS, 3 SQL_ID, 4 LAST_CALL_ET, 5 BLOCKING_INSTANCE, 6 BLOCKING_SESSION, 7 EVENT 8 FROM GV$SESSION 9 WHERE BLOCKING_SESSION IS NOT NULL;
SID STATUS SQL_ID LAST_CALL_ET BLOCKING_INSTANCE BLOCKING_SESSION EVENT ---------- -------- ------------- ------------ ----------------- ---------------- --------------------- 162 ACTIVE 2kvrfkkjukryr 4875 1 27 enq: TM - contention
SYS@lhrdb S3> select sql_text from v$sql where sql_id='2kvrfkkjukryr';
SQL_TEXT ---------------------------------------------------- INSERT /*+ APPEND */ INTO T_APPEND_161107_LHR SELECT * FROM DUAL
SYS@lhrdb S3> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID IN (27, 162);
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- ----- --------------------- ------------- ------------- ------------ --------------- 27 SYS T_APPEND_161107_LHR Exclusive None 647 Blocking 162 SYS T_APPEND_161107_LHR None Exclusive 468 Not Blocking |
從視圖DBA_DML_LOCKS能夠很是直觀的看出鎖的狀況,會話1即SID爲27,擁有Exclusive的排它鎖,沒有請求其它鎖,而會話2即SID爲162正在請求Exclusive的排它鎖。
SELECT * FROM V$EVENT_NAME WHERE NAME = 'enq: TM - contention';
從會話查詢鎖的信息:
SELECT SID,
STATUS,
SQL_ID,
LAST_CALL_ET,
EVENT,
A.P1,
A.P2,
A.P3,
CHR(BITAND(P1, -16777216) / 16777215) ||
CHR(BITAND(P1, 16711680) / 65535) "LOCK",
BITAND(P1, 65535) "MODE",
(SELECT OBJECT_NAME FROM DBA_OBJECTS D WHERE D.OBJECT_ID = A.P2) OBJECT_NAME
FROM GV$SESSION A
WHERE A.EVENT = 'enq: TM - contention';
會話1提交,查看會話2的狀況:
SYS@lhrdb S1> commit;
Commit complete.
SYS@lhrdb S1> 會話2: SYS@lhrdb S2> INSERT /*+ APPEND */ INTO T_APPEND_161107_LHR SELECT * FROM DUAL;
3 rows created.
SYS@lhrdb S2> SYS@lhrdb S2> SYS@lhrdb S2> commit;
Commit complete.
SYS@lhrdb S2> SELECT * FROM V$LOCK T WHERE T.SID IN (27,162) AND T.TYPE IN ('TX','TM') ORDER BY T.SID ;
no rows selected
|
執行不一樣的 DML 語句時,Oracle自動地對數據加鎖。
執行查詢(query)的 SQL 語句不易與其餘 SQL 語句衝突,由於查詢只需讀取數據。除了 SELECT 以外,INSERT,UPDATE,及 DELETE 語句中也可能包含隱式的查詢。所以,如下語句都屬於查詢操做:
SELECT
INSERT ... SELECT ... ;
UPDATE ... ;
DELETE ... ;
可是如下語句不屬於查詢操做:
SELECT ... FOR UPDATE OF ... ;
查詢操做具有如下特性:
l 查詢無需獲取數據鎖。所以當某事務查詢數據表時,其它事務能夠併發地查詢、更新同一個表,包括此表中正在被查詢的數據行。沒有使用 FOR UPDATE 子句的 SELECT 語句無需獲取任何數據鎖,所以也不會阻塞任何操做,此類查詢在 Oracle 中被稱爲非阻塞查詢(nonblocking query)。
l 執行查詢也不受數據鎖的限制。(在某些特殊狀況下,查詢須要等待掛起的分佈式事務所擁有的數據鎖)
INSERT,UPDATE,DELETE,及 SELECT ... FOR UPDATE 語句默認獲取的鎖有如下特色:
l 包含 DML 語句的事務須要得到被其修改的數據行上的排它行級鎖(exclusive row lock)。在擁有鎖的事務提交或回滾前,其它事務不能更新或刪除被加鎖的數據行。
l 事務無需獲取 DML 語句內的子查詢(subquery)或隱式查詢(implicit query)(例如 WHERE 子句內的查詢)所選擇的行上的行級鎖。DML 內的子查詢或隱式查詢得到的數據相對查詢開始的時間點知足一致性,這些查詢不會看到 DML 語句自身對數據的影響。
l 事務內的查詢可以看到本事務內以前執行的 DML 語句對數據的修改,但沒法看到本事務開始後執行的其它事務對數據的修改。
l 事務內的 DML 語句除了須要得到必要的排它行級鎖(exclusive row lock)外,至少還需得到包含被修改數據行的表上的行排它表級鎖(row exclusive table lock)。若是事務已經得到了相關表上的共享表級鎖(share),共享行排它表級鎖(share row exclusive),或排它表級鎖(exclusive),那麼就無需獲取行排它表級鎖了。若是事務已經得到了相關表上的行共享表級鎖(row share table lock),Oracle 將自動地將此鎖轉換爲行排它表級鎖。
當某個運行中的DDL操做正在操做或引用某模式對象時,數據字典(DDL)鎖保護該模式對象的定義。在DDL操做的過程當中,只有被修改或引用的單個模式的對象被鎖定。數據庫毫不會鎖定整個數據字典。
Oracle數據庫將爲任何要求鎖的DDL事務自動獲取DDL鎖。用戶不能顯式請求DDL鎖。例如,若是用戶建立一個存儲過程,則數據庫自動爲過程定義中引用的全部模式對象獲取DDL鎖。DDL鎖防止在過程編譯完成以前,這些對象被更改或刪除。
數據字典鎖(data dictionary lock,DDL)的做用是在執行 DDL 操做時對被修改的方案對象或其引用對象的定義進行保護。管理員及開發者應該意識到 DDL 語句將會隱式地提交一個事務。例如,用戶建立一個存儲過程時,至關於執行一個只包含一條 SQL 語句的事務,Oracle 會自動獲取過程定義中所引用的全部方案對象的 DDL 鎖。DDL 鎖可以防止編譯期間過程所引用的對象被其它事務修改或移除。
當 DDL 事務須要時 Oracle 將自動地爲其獲取數據字典鎖。用戶不能顯示地獲取 DDL 鎖。只有在 DDL 操做中被修改或引用的對象纔會被加鎖,整個數據字典不會被加鎖。
當用戶發佈DDL(Data Definition Language)語句時會對涉及的對象加DDL鎖。因爲DDL語句會更改數據字典,因此該鎖也被稱爲字典鎖。
DDL鎖能防止在用DML語句操做數據庫表時,對錶進行刪除,或對錶的結構進行更改。
對於DDL鎖,要注意的是:
l DDL鎖只鎖定DDL操做所涉及的對象,而不會鎖定數據字典中的全部對象。
l DDL鎖由Oracle自動加鎖和釋放。不能顯式地給對象加DDL鎖,即沒有加DDL鎖的語句。
l 在過程當中引用的對象,在過程編譯結束以前不能被改變或刪除,即不能被加排它DDL鎖。
DDL 鎖能夠分爲三類:排它 Ddl 鎖(Exclusive DDL Lock),共享 Ddl 鎖(Share DDL Lock),及可中斷的解析鎖(Breakable Parse Lock)。
大多數DDL 都帶有一個排它DDL 鎖。若是發出以下一條語句:
Alter table t add new_column date;
在執行這條語句時,表T 不能被別人修改。在此期間,可使用SELECT 查詢這個表,可是大多數其餘操做都不容許執行,包括全部DDL 語句。
獨佔DDL鎖可防止其它會話獲取DDL或DML鎖。除了那些在"共享DDL鎖"中所述操做以外,絕大多數DDL操做須要對資源獲取獨佔鎖,以防止和其它可能會修改或引用相同模式對象的DDL之間的破壞性干擾。例如,當ALTER TABLE正在將一列添加到表時,不容許DROP TABLE刪除表,反之亦然。
獨佔DDL鎖在整個DDL語句執行期間一直持續,並自動提交。在獨佔DDL鎖獲取過程當中,若是另外一個操做在該模式對象上持有另外一個DDL鎖,則這個鎖獲取將一直等待,直到前一個DDL鎖被釋放,才能繼續。
create index t_idx on t(x) ONLINE;
ONLINE 關鍵字會改變具體創建索引的方法。Oracle 並非加一個排它DDL 鎖 防止數據修改,而只會試圖獲得表上的一個低級 (mode 2 )TM 鎖。這會有效地防止其餘DDL 發生,同時還容許DML 正常進行。Oracle 執行這一壯舉」的作法是,爲DDL 語句執行期 間對錶所作的修改維護一個記錄,執行CREATE 時再把這些修改應用至新的索引。這樣能大大增長數據的可用性。
另一類DDL 會得到共享DDL 鎖。在建立存儲的編譯對象(如過程和視圖)時,會對依賴的對象加這種共享DDL 鎖。例如,若是 執行如下語句:
Create view MyView as select * from emp, dept where emp.deptno = dept.deptno;
表EMP 和DEPT 上都會加共享DDL 鎖,而CREATE VIEW 命令仍在處理。能夠修改這些表的內容,可是不能修改它們的結構。
A share DDL lock for a resource prevents destructive interference with conflicting DDL operations, but allows data concurrency for similar DDL operations.
在資源上的共享DDL鎖可防止與衝突的DDL操做發生破壞性干擾,但容許相似的DDL操做的數據併發。
例如,當CREATE PROCEDURE語句運行時,所在事務將爲全部被引用的表獲取共享DDL鎖。其它事務能夠同時建立引用相同表的過程,並在相同的表上同時得到共享DDL鎖,但沒有任何事務能在任何被引用表上獲取獨佔DDL鎖。
共享DDL鎖在整個DDL語句執行期間持續存在,並自動提交。所以,持有一個共享DDL鎖的事務,可保證在事務過程當中,被引用模式對象的定義保持不變。
某些 DDL 操做須要獲取相關資源上的共享 DDL 鎖(share DDL lock)以防止與之衝突的 DDL 操做形成破壞性的干擾,但與之相似的 DDL 操做能夠併發地訪問數據,不受共享 DDL 鎖的限制。例如,執行 CREATE PROCEDURE 語句時,事務將獲取全部引用對象上的共享 DDL 鎖。此時,其它事務能夠併發地獲取相同表上的共享 DDL 鎖並建立引用了相同表的過程。但任何事務都沒法獲取被引用表上的排它 DDL 鎖(exclusive DDL lock),即任何事務都沒法對錶進行修改或移除操做。所以得到了共享 DDL 鎖的事務可以保證在其執行期間,全部引用對象的定義不會被修改。
執行如下 DDL 語句時,須要獲取引用對象上的共享 DDL 鎖:AUDIT,NOAUDIT,COMMENT,CREATE [OR REPLACE] VIEW/ PROCEDURE/PACKAGE/PACKAGE BODY/FUNCTION/ TRIGGER,CREATE SYNONYM,及 CREATE TABLE(沒有使用 CLUSTER 參數時)。
SQL語句或PL/SQL程序單元,爲每一個被其引用的模式對象持有一個解析鎖。獲取解析鎖的目的是,若是被引用的對象被更改或刪除,可使相關聯的共享SQL區無效。解析鎖被稱爲可中斷的解析鎖,由於它並不由止任何DDL操做,並能夠被打破以容許衝突的DDL操做。
解析鎖是在執行SQL語句的分析階段,在共享池中獲取的。只要該語句的共享SQL區仍保留在共享池中,該鎖就一直被持有。
位於共享池(shared pool)內的 SQL 語句(或 PL/SQL 程序結構)擁有其引用的全部方案對象上的解析鎖(parse lock)。解析鎖的做用是,當共享 SQL 區(shared SQL area)所引用的對象被修改或移除後,此共享 SQL 區可以被置爲無效。解析鎖不會禁止任何 DDL 操做,當出現與解析鎖衝突的 DDL 操做時,解析鎖將被解除,所以也稱之爲可解除的解析鎖。
解析鎖是在 SQL 語句執行的解析階段(parse phase)得到的,在共享 SQL 區被清除出共享池(shared pool)前一直保持。
你的會話解析一條語句時,對於該語句引用的每個對象都會加一個解析鎖。加這些鎖的目的是:若是以某種方式刪除或修改了一個被引用的對象,能夠將共享池中已解析的緩存語句置爲無效(刷新輸出)。
CREATE OR REPLACE PROCEDURE P_BPL_LHR AS BEGIN NULL; END;
|
要看到一個實際的可中斷解析鎖,下面先建立並運行存儲過程P_BPL_LHR:
SYS@lhrdb> CREATE OR REPLACE PROCEDURE P_BPL_LHR AS 2 BEGIN 3 NULL; 4 END; 5 /
Procedure created.
SYS@lhrdb> exec P_BPL_LHR;
PL/SQL procedure successfully completed.
SYS@lhrdb> SELECT DISTINCT SID FROM V$MYSTAT;
SID ---------- 194
|
過程P_BPL_LHR如今會出如今DBA_DDL_LOCKS 視圖中。咱們有這個過程的一個解析鎖:
SELECT * FROM DBA_DDL_LOCKS D WHERE D.SESSION_ID = 194;
而後從新編譯這個過程,並再次查詢視圖:
SYS@lhrdb> ALTER PROCEDURE P_BPL_LHR COMPILE;
Procedure altered.
|
能夠看到,如今這個視圖中沒有P_BPL_LHR了。咱們的解析鎖被中斷了。這個視圖對 發人員頗有用,發現測試或開發系統中某段代碼沒法編譯時,將會掛起並最終超時。這說明,有人正在使用這段代碼 (實際上在運行這段代碼),你可使用這個視圖 查看這我的是誰。對於GRANTS 和對象的其餘類型的DDL 也是同樣。例如,沒法對正在運行的過程授予EXECUTE 權限。可使用一樣的方法 發現潛在的阻塞者和等待者。
DDL 鎖的持續時間取決於其類型。共享 DDL 鎖(share DDL lock)及排它 DDL 鎖(exclusive DDL lock)在 DDL 語句執行期間一直存在,在 DDL 語句自動提交後釋放。而解析鎖一直存在,直至相關的共享 SQL 區從共享池中被清除。
對簇(cluster)執行的 DDL 操做須要獲取簇及簇內全部表及物化視圖上的排它 DDL 鎖(exclusive DDL lock)。對簇內表及物化視圖的 DDL 操做須要獲取簇上的共享 DDL 鎖(share DDL lock),以及表或物化視圖上的共享 DDL 鎖或排它 DDL 鎖。簇上的共享 DDL 鎖可以防止操做期間其餘 DDL 操做將簇移除。
Oracle數據庫使用各類類型的系統鎖,來保護數據庫內部和內存結構。因爲用戶不能控制其什麼時候發生或持續多久,這些機制對於用戶幾乎是不可訪問的。閂鎖、互斥體、和內部鎖是徹底自動的。
閂鎖(latche)是一種簡單的底層串行化機制,用於保護 SGA 內的共享數據結構。例如,用於記錄當前正在訪問數據庫的用戶的列表,或用於記錄位於數據庫緩存(buffer cache)內的數據塊的數據結構,均可經過閂鎖進行保護。當服務進程(background process)或後臺進程(server process)須要操做或查詢此類數據結構時,就須要獲取一個閂鎖,但其加鎖時間極短。閂鎖的實現與操做系統有關,例如進程是否須要等待栓鎖以及等待多長時間等。
閂鎖是簡單、低級別的串行化機制,用於協調對共享數據結構、對象、和文件的多用戶訪問。閂鎖防止共享內存資源被多個進程訪問時遭到破壞。具體而言,閂鎖在如下狀況下保護數據結構:
l 被多個會話同時修改
l 正在被一個會話讀取時,又被另外一個會話修改
l 正在被訪問時,其內存被釋放(換出)
一般,一個單一的閂鎖保護SGA中的多個對象。例如,後臺進程(如DBWn和LGWR)從共享池分配內存來建立數據結構。爲分配此內存,這些進程使用共享池閂鎖來串行化對內存的訪問,以防止兩個進程同時嘗試檢查或修改共享池。內存分配後,其它進程可能須要訪問共享池區域,如用於解析所需的庫高速緩存。在這種狀況下,進程只在庫緩存獲取閂鎖,而不是在整個共享池。
與行鎖之類的入隊閂鎖不一樣,閂鎖不容許會話排隊。當閂鎖可用時,請求閂鎖的第一個會話將得到它的獨佔訪問權限。閂鎖旋轉(Latch spinning)發生在當一個進程不斷地循環來請求一個閂鎖時,而閂鎖睡眠(latch sleeping)發生在從新發起閂鎖請求以前,釋放CPU時。
一般,一個Oracle進程在操做或查看一種數據結構時,只需在一個極短的時間內得到閂鎖。例如,僅僅爲某一名員工處理工資更新,數據庫就可能須要獲取並釋放成千上萬個閂鎖。閂鎖的實現依賴於操做系統,特別是在一個進程是否會在閂鎖上等待以及會在閂鎖等待多長時間方面。
閂鎖的增長意味着併發的下降。例如,過分硬解析操做會產生庫緩存閂鎖爭用。V$LATCH視圖包含每一個閂鎖的詳細使用狀況的統計信息,包括每一個閂鎖被請求和被等待的次數。
互斥對象(mutual exclusion object,mutex),也叫互斥體,它是一種底層機制,用於防止在內存中的對象在被多個併發進程訪問時,被換出內存或遭到破壞。互斥對象相似於閂鎖,但閂鎖一般保護一組對象,而互斥對象一般保護單個對象。
互斥對象提供如下幾個優勢:
一、 互斥體能夠減小發生爭用的可能性。
因爲閂鎖保護多個對象,當多個進程試圖同時訪問這些對象的任何一個時,它可能成爲一個瓶頸。而互斥體僅僅串行化對單個對象的訪問,而不是一組對象,所以互斥體提升了可用性。
二、 互斥體比閂鎖消耗更少的內存。
三、 在共享模式下,互斥體容許被多個會話併發引用。
內部鎖是比閂鎖和互斥體更高級、更復雜的機制,並用於各類目的。數據庫使用如下類型的內部鎖:
一、 字典緩存鎖(Dictionary cache locks)
這些鎖的持續時間很短,當字典緩存中的條目正在被修改或使用時被持有。它們保證正在被解析的語句不會看到不一致的對象定義。字典緩存鎖能夠是共享的或獨佔的。共享鎖在解析完成後被釋放,而獨佔鎖在DDL操做完成時釋放。
當用戶更新或使用時數據字典緩存內的條目(entry)時,須要獲取條目上的數據字典緩存鎖(dictionary cache lock),此類鎖的持續時間極短。此類鎖的做用是確保正在被解析的語句不會看到不一致的對象定義。數據字典緩存鎖能夠爲共享或排它的。當語句解析結束時共享鎖將被釋放,而當 DDL 操做結束時排它鎖將被釋放。
二、 文件和日誌管理鎖(File and log management locks)
這些鎖保護各類文件。例如,一種內部鎖保護控制文件,以便一次只有一個進程能夠對其進行更改。而另外一種鎖用於協調聯機重作日誌文件的使用和歸檔。數據文件被鎖定,確保數據庫被多個實例以共享模式裝載,或以獨佔模式被單個實例裝載。由於文件和日誌鎖表示文件的狀態,這些鎖必要時會被持有較長一段時間。
此類內部鎖(internal lock)用於保護各類文件。例如,保護控制文件(control file)的鎖,確保同一時間只有一個進程可以對其進行修改。還有協調重作日誌文件(redo log file)使用與歸檔的鎖。以及數據文件(datafile)鎖,實現多實例在共享模式下掛載數據庫,或一個實例在排它模式下掛載數據庫。因爲文件及重作日誌鎖反映的是 物理文件的狀態,所以此類鎖的持續時間較長。
三、 表空間和撤銷段鎖(Tablespace and undo segment locks)
這些鎖保護的表空間和撤銷段。例如,訪問數據庫的全部實例對一個表空間是否處於聯機或脫機必須保持一致。撤銷段被鎖定,以便只能有一個數據庫實例能夠寫入該段。
此類鎖用於保護表空間及回滾段(rollback segment)。例如,一個表空間處於聯機(online)仍是脫機(offline)狀態對訪問同一數據庫的全部實例應該是一致的。回滾段上的鎖保證 同一時間只有一個實例可以對其執行寫操做。
有關死鎖的內容以前發佈過一次,具體內容參考:http://blog.itpub.net/26736162/viewspace-2127247/,本篇文章再也不講解。
經常使用的數據字典視圖有DBA_DML_LOCKS、DBA_DDL_LOCKS、V$LOCK、DBA_LOCK、V$LOCKED_OBJECT。
---查詢的都是當前實例的鎖
select * from dba_dml_locks;
select * from dba_ddl_locks d where d.owner not in('SYS','WMSYS','MDSYS');
select * from DBA_LOCK V where V.session_id=23;
select * from V$LOCK V where V.SID=23;
select * from V$LOCK_TYPE;
select * from V$LOCKED_OBJECT;
本視圖列出Oracle 服務器當前擁有的鎖以及未完成的鎖或栓鎖請求。
v$lock和dba_locks和 dba_lock 內容同樣,dba_locks是dba_lock的同義詞。能夠用動態性能視圖的定義來查看它們的關係V$FIXED_VIEW_DEFINITION。
SELECT * FROM Dba_Objects d WHERE d.object_name LIKE '%DBA_LOCK%' ;
SELECT * FROM Dba_Synonyms d WHERE d.synonym_name LIKE '%DBA_LOCK%' ;
SELECT * FROM V$FIXED_VIEW_DEFINITION d WHERE d.VIEW_NAME LIKE '%V$LOCK%' ;
注意:V$LOCKED_OBJECT記錄的是DML鎖信息,DDL鎖的信息不在裏面。
這個視圖列出系統上的每一個事務處理所得到的全部鎖。記錄了當前已經被鎖定的對象的信息
XIDUSN表示當前事務使用的回滾段的編號
XIDSLOT說明該事務在回滾段頭部的事務表中對應的記錄編號
XIDSQN說明序列號
OBJECT_ID說明當前被鎖定的對象的ID號,能夠根據該ID號到dba_objects裏查找被鎖定的對象名稱
LOCKED_MODE說明鎖定模式的數字編碼
V$LOCKED_OBJECT中的列說明:
示例:1.以DBA角色查看當前數據庫裏鎖的狀況能夠用以下SQL語句:
SELECT v.object_id,
d.OBJECT_NAME,
d.OBJECT_TYPE,
locked_mode,
v2.username,
v2.sid,
v2.serial#,
v2.logon_time
FROM v$locked_object v,
dba_objects d,
v$session v2
WHERE v.OBJECT_ID = d.OBJECT_ID
AND v.SESSION_ID = v2.SID
ORDER BY v2.logon_time;
v$locked_object視圖列出當前系統中哪些對象正被鎖定.
v$lock視圖列出當前系統持有的或正在申請的全部鎖的狀況.
DBA_DDL_LOCKS lists all DDL locks held in the database and all outstanding requests for a DDL lock.
查詢全部DDL鎖的信息:
SELECT * FROM DBA_DDL_LOCKS D WHERE D.SESSION_ID = 115;
若是提示沒有這個視圖,能夠在sys用戶下執行$ORACLE_HOME/rdbms/admin/catblock.sql腳本進行建立(這個腳本還包含其餘一些很是有意義的鎖相關視圖)
sys@ora10g> conn / as sysdba
Connected.
sys@ora10g> @?/rdbms/admin/catblock.sql
這裏省略建立過程
打印一下catblock.sql腳本的內容,這個建立腳本其實能夠當作一個參考文檔來用,尤爲是其中關於鎖類型的描述。
DBA_DML_LOCKS lists all DML locks held in the database and all outstanding requests for a DML lock.
SQL> CREATE TABLE TB_DML_LOCK_LHR (ID NUMBER);
Table created.
SQL> INSERT INTO TB_DML_LOCK_LHR VALUES(1);
1 row created.
SQL> set line 9999 SQL> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- ------- ------------------ ------------- ------------- ------------ ----------------- 151 SYS TB_DML_LOCK_LHR Row-X (SX) None 10 Not Blocking
SQL>
|
會話1: SYS@oratest S1> select distinct sid from v$mystat;
SID ---------- 22
SYS@oratest S1> CREATE TABLE SCOTT.EMP_LHR AS SELECT * FROM SCOTT.EMP;
Table created.
SYS@oratest S1> delete from scott.EMP_LHR where empno=7369;
1 row deleted.
SYS@oratest S1>
會話2: SYS@oratest S2> select distinct sid from v$mystat;
SID ---------- 143
SYS@oratest S2> delete from scott.EMP_LHR where empno=7369;
====>>>>> 產生了阻塞
會話3查詢鎖: SQL> set line 9999 SQL> SELECT A.TADDR, 2 A.LOCKWAIT, 3 A.ROW_WAIT_OBJ#, 4 A.ROW_WAIT_FILE#, 5 A.ROW_WAIT_BLOCK#, 6 A.ROW_WAIT_ROW#, 7 A.EVENT, 8 A.P1, 9 A.P2, 10 A.SID, 11 A.BLOCKING_SESSION 12 FROM V$SESSION A 13 WHERE A.SID IN (22, 143); TADDR LOCKWAIT ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW# EVENT P1 P2 SID BLOCKING_SESSION ---------------- ---------------- ------------- -------------- --------------- ------------- ------------------------------ ---------- ---------- ---------- ---------------- 000000007622B710 -1 0 0 0 SQL*Net message from client 1650815232 1 22 000000007622AD00 00000000774DA0C0 77669 8 2799 0 enq: TX - row lock contention 1415053318 524299 143 22
|
V$SESSION視圖的TADDR列表示事務處理狀態對象的地址,對應於V$TRANSACTION.ADDR列;V$SESSION視圖的LOCKWAIT列表示等待鎖的地址,對應於V$LOCK的KADDR列;若當前會話沒有被阻塞則爲空。V$SESSION視圖的SADDR列對應於V$TRANSACTION的SES_ADDR列。能夠經過ROW_WAIT_OBJ#、ROW_WAIT_FILE#、ROW_WAIT_BLOCK#、ROW_WAIT_ROW#這幾個字段查詢如今正在被鎖的表的相關信息(ROWID),例如,表名、文件名及行號。P1和P2根據等待事件的不一樣所表明的含義不一樣,能夠從V$EVENT_NAME視圖獲知每一個參數的含義。
SQL> SELECT D.PARAMETER1,D.PARAMETER2,D.PARAMETER3 FROM V$EVENT_NAME D WHERE D.NAME='enq: TX - row lock contention';
PARAMETER1 PARAMETER2 PARAMETER3 ------------ --------------- ---------- name|mode usn<<16 | slot sequence
SQL> SELECT CHR(BITAND(P1, -16777216) / 16777215) || 2 CHR(BITAND(P1, 16711680) / 65535) "LOCK", 3 BITAND(P1, 65535) "MODE", 4 TRUNC(P2 / POWER(2, 16)) AS XIDUSN, 5 BITAND(P2, TO_NUMBER('FFFF', 'XXXX')) + 0 AS XIDSLOT, 6 P3 XIDSQN 7 FROM V$SESSION A 8 WHERE A.SID IN (143);
LOCK MODE XIDUSN XIDSLOT XIDSQN ---- ---------- ---------- ---------- ---------- TX 6 4 30 894
<<<<<---從P1參數獲知請求的鎖的類型和模式;從P2參數能夠獲知槽位號
SQL> SELECT ADDR,XIDUSN,XIDSLOT,XIDSQN FROM v$transaction a WHERE a.ADDR IN ('000000007622B710');
ADDR XIDUSN XIDSLOT XIDSQN ---------------- ---------- ---------- ---------- 000000007622B710 4 30 894
SQL> SELECT ADDR,XIDUSN,XIDSLOT,XIDSQN FROM v$transaction a WHERE a.SES_ADDR ='0000000077E6F600';
ADDR XIDUSN XIDSLOT XIDSQN ---------------- ---------- ---------- ---------- 000000007622B710 4 30 894
SQL> SELECT * FROM V$LOCK A WHERE A.SID IN (22, 143) AND A.TYPE IN ('TX','TM') AND A.KADDR='00000000774DA0C0' ORDER BY a.SID,a.TYPE;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00000000774DA068 00000000774DA0C0 143 TX 262174 894 0 6 658 0
SQL> SELECT DBMS_ROWID.ROWID_CREATE(1, 77766, 4, 131, 0) FROM DUAL;
DBMS_ROWID.ROWID_C ------------------ AAAS/GAAEAAAACDAAA
SQL> SELECT * FROM SCOTT.EMP A WHERE A.ROWID='AAAS/GAAEAAAACDAAA';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
SQL>
|
能夠看到被鎖的行的地址。
SQL> SELECT * FROM V$LOCK A WHERE A.SID IN (22, 143) AND A.TYPE IN ('TX','TM') ORDER BY a.SID,a.TYPE;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007FF44BF72D18 00007FF44BF72D78 22 TM 77766 0 3 0 793 0 000000007622B710 000000007622B788 22 TX 262174 894 6 0 793 1 00007FF44BF72D18 00007FF44BF72D78 143 TM 77766 0 3 0 787 0 00000000774DA068 00000000774DA0C0 143 TX 262174 894 0 6 787 0 6 rows selected.
SQL> SQL> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID IN (22, 143) ORDER BY d.SESSION_ID;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- -------- -------- ------------- ------------- ------------ --------------- 22 SCOTT EMP_LHR Row-X (SX) None 1146 Not Blocking 143 SCOTT EMP_LHR Row-X (SX) None 1140 Not Blocking
SQL> SELECT D.OWNER, D.OBJECT_NAME, D.OBJECT_ID, D.OBJECT_TYPE 2 FROM DBA_OBJECTS D 3 WHERE D.OBJECT_ID IN (77766);
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE -------- ------------ ---------- ------------------- SCOTT EMP_LHR 77766 TABLE
SQL> SQL> SELECT a.XIDUSN, 2 a.XIDSLOT, 3 a.XIDSQN FROM v$transaction a WHERE a.XIDSQN =894;
XIDUSN XIDSLOT XIDSQN ---------- ---------- ---------- 4 30 894 SQL> SELECT 4*POWER(2,16)+30 FROM DUAL;
4*POWER(2,16)+30 ---------------- 262174
SQL> SQL> SELECT TRUNC(ID1 / POWER(2, 16)) AS XIDUSN, 2 BITAND(ID1, TO_NUMBER('FFFF', 'XXXX')) + 0 AS XIDSLOT, 3 894 XIDSQN 4 FROM V$LOCK A 5 WHERE A.SID IN (22, 143) 6 AND A.TYPE IN ('TX', 'TM') 7 AND A.ADDR = '000000007622B710' 8 ORDER BY A.SID, A.TYPE;
XIDUSN XIDSLOT XIDSQN ---------- ---------- ---------- 4 30 894
|
在V$LOCK中,當TYPE列的值爲TM時,ID1的值爲DBA_OBJECTS.OBJECT_ID;當爲TX鎖時,ID1對應視圖V$TRANSACTION中的XIDUSN字段(Undo segment number:事務對應的撤銷段序列號)和XIDSLOT字段(Slot number:事務對應的槽位號)。其中ID1的高16位爲XIDUSN,低16位爲XIDSLOT。計算公式爲:SELECT TRUNC(ID1/POWER(2,16)) AS XIDUSN,BITAND(ID1,TO_NUMBER('FFFF','XXXX')) + 0 AS XIDSLOT , ID2 XIDSQN FROM DUAL;
在V$LOCK中,當TYPE列的值爲TM鎖時,ID2的值爲0;當爲TX鎖時,ID2對應視圖V$TRANSACTION中的XIDSQN字段(Sequence number:事務對應的序列號)。
從V$SESSION視圖能夠獲得全部內容:
SELECT A.TADDR,
A.LOCKWAIT,
A.ROW_WAIT_OBJ#,
A.ROW_WAIT_FILE#,
A.ROW_WAIT_BLOCK#,
A.ROW_WAIT_ROW#,
(SELECT D.OWNER || '|' || D.OBJECT_NAME || '|' || D.OBJECT_TYPE
FROM DBA_OBJECTS D
WHERE D.OBJECT_ID = A.ROW_WAIT_OBJ#) OBJECT_NAME,
A.EVENT,
A.P1,
A.P2,
A.P3,
CHR(BITAND(P1, -16777216) / 16777215) ||
CHR(BITAND(P1, 16711680) / 65535) "LOCK",
BITAND(P1, 65535) "MODE",
TRUNC(P2 / POWER(2, 16)) AS XIDUSN,
BITAND(P2, TO_NUMBER('FFFF', 'XXXX')) + 0 AS XIDSLOT,
P3 XIDSQN,
A.SID,
A.BLOCKING_SESSION,
A.SADDR,
DBMS_ROWID.ROWID_CREATE(1, 77669, 8, 2799, 0) REQUEST_ROWID,
(SELECT B.SQL_TEXT
FROM V$SQL B
WHERE B.SQL_ID = NVL(A.SQL_ID, A.PREV_SQL_ID)) SQL_TEXT
FROM V$SESSION A
WHERE A.SID IN (143);
能夠得到的TX鎖定的總個數由初始化參數transactions決定,而能夠得到的TM鎖定的個數則由初始化參數dml_locks決定
select name,value from v$parameter where name in('transactions','dml_locks');
SYS@racdb1> col name format a15 SYS@racdb1> col value format a5 SYS@racdb1> select name,value from v$parameter where name in('transactions','dml_locks');
NAME VALUE --------------- ----- dml_locks 1088 transactions 272
SYS@racdb1> select 272*4 from dual;
272*4 ---------- 1088
|
DML_LOCKS參數屬於推導參數,DML_LOCKS=4 * TRANSACTIONS。
select resource_name as "R_N",current_utilization as "C_U",max_utilization as "M_U",initial_allocation as "I_U"
from v$resource_limit
where resource_name in('transactions','dml_locks');
SYS@racdb1> select resource_name as "R_N",current_utilization as "C_U",max_utilization as "M_U",initial_allocation as "I_U" 2 from v$resource_limit 3 where resource_name in('transactions','dml_locks');
R_N C_U M_U I_U ------------------------------ ---------- ---------- -------------------- dml_locks 0 28 1088 transactions 0 6 272
|
系統中容許的TM 鎖總數能夠由你配置(有關細節請見Oracle Database Reference 手冊中的DML_LOCKS 參數定義)。實際上,這個數可能設置爲0。但這並非說你的數據庫變成了一個只讀數據庫(沒有鎖),而是說不容許DDL。在很是專業的應用(如RAC 實現)中,這一點就頗有用,能夠減小實例內可能發生的協調次數。經過使用ALTER TABLE TABLENAME DISABLE TABLE LOCK 命令,還能夠逐對象地禁用TM 鎖。這是一種快捷方法,可使意外刪除表的難度更大」,由於在刪除表以前,你必須從新啓用表鎖。還能用它檢測因爲外鍵未加索引而致使的全表鎖(前面已經討論過)。
Property |
Description |
Parameter type |
Integer |
Default value |
Derived: 4 * TRANSACTIONS |
Modifiable |
No |
Range of values |
20 to unlimited; a setting of 0 disables enqueues |
Basic |
No |
Oracle RAC |
You must set this parameter for every instance, and all instances must have positive values or all must be 0. |
A DML lock is a lock obtained on a table that is undergoing a DML operation (insert, update, delete). DML_LOCKS specifies the maximum number of DML locks—one for each table modified in a transaction. The value should equal the grand total of locks on tables currently referenced by all users. For example, if three users are modifying data in one table, then three entries would be required. If three users are modifying data in two tables, then six entries would be required.
The default value assumes an average of four tables referenced for each transaction. For some systems, this value may not be enough.
Enqueues are shared memory structures that serialize access to database resources. If you set the value of DML_LOCKS to 0, enqueues are disabled and performance is slightly increased. However, you should be aware of the following restrictions when you set you DML_LOCKS to 0:
l You cannot use DROP TABLE, CREATE INDEX statements
l You cannot use explicit lock statements such as LOCK TABLE IN EXCLUSIVE MODE
l Enterprise Manager cannot run on any instances for which DML_LOCKS is set to 0
Oracle holds more locks during parallel DML than during serial execution. Therefore, if your database supports a lot of parallel DML, you may need to increase the value of this parameter.
11g之前,DDL 語句是不會等待DML語句的,當DDL語句訪問的對象正在執行的DML語句,會當即報錯ORA-00054: 資源正忙, 但指定以 NOWAIT 方式獲取資源, 或者超時失效。而在11g之後,DDL_LOCK_TIMEOUT參數能夠修改這一狀態,當DDL_LOCK_TIMEOUT=0時,DDL 不等待DML,當DDL_LOCK_TIMEOUT 爲N(秒)時,DDL等待DML N 秒,該值默認爲0。
Property |
Description |
Parameter type |
Integer |
Default value |
0 |
Modifiable |
ALTER SESSION |
Range of values |
0 to 1,000,000 (in seconds) |
Basic |
No |
DDL_LOCK_TIMEOUT specifies a time limit for how long DDL statements will wait in a DML lock queue. The default value of zero indicates a status of NOWAIT. The maximum value of 1,000,000 seconds will result in the DDL statement waiting forever to acquire a DML lock.
If a lock is not acquired before the timeout period expires, then an error is returned.
會話1:
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> set sqlprompt "_user'@'_connect_identifier S1> " SYS@oratest S1> set timing on SYS@oratest S1> update scott.emp set ename='' where empno=7499;
1 row updated.
Elapsed: 00:00:00.00 SYS@oratest S1>
|
會話2:
SQL> set sqlprompt "_user'@'_connect_identifier S2> " SYS@oratest S2> set timing on SYS@oratest S2> drop table scott.emp; drop table scott.emp * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
Elapsed: 00:00:00.74 SYS@oratest S2> show parameter ddl_lock_timeout
NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ ddl_lock_timeout integer 0 SYS@oratest S2> alter session set ddl_lock_timeout=5;
Session altered.
Elapsed: 00:00:00.00 SYS@oratest S2> drop table scott.emp; drop table scott.emp * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
Elapsed: 00:00:05.01 SYS@oratest S2> alter session set ddl_lock_timeout=10;
Session altered.
Elapsed: 00:00:00.00 SYS@oratest S2> drop table scott.emp; drop table scott.emp * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
Elapsed: 00:00:10.03 SYS@oratest S2>
|
綜上,設置ddl_lock_timeout爲N(秒)後,DDL執行後將等待N秒鐘後才拋出報錯信息。在ddl_lock_timeout爲默認值 0 時,DDL語句提交以後立刻報錯。
SELECT...FOR UPDATE 語句的語法以下:
SELECT ... FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
其中:
l OF 這個OF子句在牽連到多個表時,具備較大做用,如不使用OF指定鎖定的表的列,則全部表的相關行均被鎖定,若在OF中指定了需修改的列,則只有與這些列相關的表的行纔會被鎖定。
l WAIT 子句指定等待其餘用戶釋放鎖的秒數,防止無限期的等待。
「使用FOR UPDATE WAIT」子句的優勢以下:
1防止無限期地等待被鎖定的行;
2容許應用程序中對鎖的等待時間進行更多的控制。
3對於交互式應用程序很是有用,由於這些用戶不能等待不肯定
4 若使用了skip locked,則能夠越過鎖定的行,不會報告由wait n 引起的‘資源忙’異常報告
for update nowait和 for update都會對所查詢到得結果集進行加鎖,所不一樣的是,若是另一個進程正在修改結果集中的數據,for update nowait不會進行資源等待,只要發現結果集中有些數據被加鎖,馬上返回「ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源」。
for update 和 for update nowait加上的是一個行級鎖,也就是隻有符合where條件的數據被加鎖。若是僅僅用update語句來更改數據時,可能會由於加不上鎖而沒有響應地、莫名其妙地等待,但若是在此以前,for update NOWAIT語句將要更改的數據試探性地加鎖,就能夠經過當即返回的錯誤提示而明白其中的道理,或許這就是For Update和NOWAIT的意義之所在。
會話1: SYS@oratest S1> SELECT EMPNO, ENAME FROM SCOTT.EMP WHERE EMPNO = '7369' FOR UPDATE NOWAIT;
EMPNO ENAME ---------- ---------- 7369 SMITH 會話2: SYS@oratest S2> SELECT EMPNO, ENAME FROM SCOTT.EMP WHERE EMPNO = '7369' FOR UPDATE NOWAIT; SELECT EMPNO, ENAME FROM SCOTT.EMP WHERE EMPNO = '7369' FOR UPDATE NOWAIT * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
上面會話都提交commit,開啓會話1,不使用NOWAIT: SYS@oratest S1> SELECT EMPNO, ENAME FROM SCOTT.EMP WHERE EMPNO = '7369' FOR UPDATE ;
EMPNO ENAME ---------- ---------- 7369 SMITH
SYS@oratest S1> 開啓另外一會話 SYS@oratest S2> SELECT EMPNO, ENAME FROM SCOTT.EMP WHERE EMPNO = '7369' FOR UPDATE ;
====>>>>> 產生了阻塞
|
阻塞,不返回錯誤。提交第一個會話,第二個回話自動執行,而後提交第二個會話
select for update of,這個of子句在牽連到多個表時,具備較大做用,如不使用of指定鎖定的表的列,則全部表的相關行均被鎖定,若在of中指定了需修改的列,則只有與這些列相關的表的行纔會被鎖定。
會話1: SYS@oratest S1> SELECT * FROM SCOTT.EMP E, SCOTT.DEPT D WHERE E.DEPTNO = D.DEPTNO FOR UPDATE;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC ---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- ---------- -------------- ------------- 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20 20 RESEARCH DALLAS 7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30 30 SALES CHICAGO 7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30 30 SALES CHICAGO 7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20 20 RESEARCH DALLAS 7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30 30 SALES CHICAGO 7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30 30 SALES CHICAGO 7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10 10 ACCOUNTING NEW YORK 7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20 20 RESEARCH DALLAS 7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10 10 ACCOUNTING NEW YORK 7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30 30 SALES CHICAGO 7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20 20 RESEARCH DALLAS 7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30 30 SALES CHICAGO 7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20 20 RESEARCH DALLAS 7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10 10 ACCOUNTING NEW YORK
14 rows selected. 會話2: SYS@oratest S2> SELECT * FROM SCOTT.DEPT FOR UPDATE NOWAIT; SELECT * FROM SCOTT.DEPT FOR UPDATE NOWAIT * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
SYS@oratest S2> SYS@oratest S2> SELECT * FROM V$LOCK A WHERE A.SID IN (16,27) AND A.TYPE IN ('TX','TM') ORDER BY a.SID,a.TYPE;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F8FABF13398 00007F8FABF133F8 16 TM 77667 0 3 0 201 0 00007F8FABF13398 00007F8FABF133F8 16 TM 77669 0 3 0 201 0 000000007620A7C0 000000007620A838 16 TX 327687 1138 6 0 201 0
SYS@oratest S2> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID IN (16,27) ORDER BY d.SESSION_ID;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- --------- ------ ------------- ------------- ------------ --------------- 16 SCOTT EMP Row-X (SX) None 225 Not Blocking 16 SCOTT DEPT Row-X (SX) None 225 Not Blocking SYS@oratest S2>
|
能夠看到,會話1在SCOTT.EMP和SCOTT.DEPT表上都加上了3級的行級排它鎖。
提交以上的會話,而後繼續試驗OF特性:
會話1: SYS@oratest S1> SELECT * FROM SCOTT.EMP E, SCOTT.DEPT D WHERE E.DEPTNO = D.DEPTNO FOR UPDATE OF SAL ;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC ---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- ---------- -------------- ------------- 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20 20 RESEARCH DALLAS 7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30 30 SALES CHICAGO 7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30 30 SALES CHICAGO 7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20 20 RESEARCH DALLAS 7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30 30 SALES CHICAGO 7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30 30 SALES CHICAGO 7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10 10 ACCOUNTING NEW YORK 7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20 20 RESEARCH DALLAS 7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10 10 ACCOUNTING NEW YORK 7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30 30 SALES CHICAGO 7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20 20 RESEARCH DALLAS 7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30 30 SALES CHICAGO 7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20 20 RESEARCH DALLAS 7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10 10 ACCOUNTING NEW YORK
14 rows selected.
會話2: SYS@oratest S2> SELECT * FROM SCOTT.DEPT FOR UPDATE NOWAIT;
DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON
SYS@oratest S2>
SYS@oratest S1> SELECT * FROM V$LOCK A WHERE A.SID IN (16,27) AND A.TYPE IN ('TX','TM') ORDER BY a.SID,a.TYPE;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F73CBCE38D8 00007F73CBCE3938 16 TM 77669 0 3 0 114 0 000000007620A7C0 000000007620A838 16 TX 327698 1138 6 0 114 0 00007F73CBCE38D8 00007F73CBCE3938 27 TM 77667 0 3 0 81 0 000000007620B1D0 000000007620B248 27 TX 131076 1128 6 0 81 0
SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID IN (16,27) ORDER BY d.SESSION_ID;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- --------- ------ ------------- ------------- ------------ --------------- 16 SCOTT EMP Row-X (SX) None 123 Not Blocking 27 SCOTT DEPT Row-X (SX) None 90 Not Blocking
SYS@oratest S1>
|
能夠看到,會話1在SCOTT.EMP表上加上了3級的行級排它鎖,而會話2在和SCOTT.DEPT表上加上了3級的行級排它鎖。
SQL*Plus: Release 9.2.0.1.0 - Production on 星期一 11月 14 17:29:40 2016
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
請輸入用戶名: sys as sysdba 請輸入口令:
鏈接到: Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production With the Partitioning, OLAP and Oracle Data Mining options JServer Release 9.2.0.1.0 - Production
SQL> set line 9999 SQL> set pagesize 9999 SQL> select * from scott.emp for update;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20 7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30 7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30 7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20 7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30 7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30 7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10 7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20 7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10 7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30 7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20 7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30 7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20 7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
已選擇14行。
SQL> select distinct sid from v$mystat;
SID ---------- 10
SQL> SELECT * FROM V$LOCK A WHERE A.SID=10 ORDER BY a.SID,a.TYPE;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 67B4E0F8 67B4E10C 10 TM 30139 0 2 0 35 0 67BAB0CC 67BAB1D8 10 TX 131082 2874 6 0 25 0
SQL> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID =10 ORDER BY d.SESSION_ID;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- --------- ------ ------------- ------------- ------------ ------------------ 10 SCOTT EMP Row-S (SS) None 99 Not Blocking
|
能夠看到在Oracle 10g以前,SELECT FOR UPDATE獲取的是2級TM鎖,在Oracle 10g及其以後的版本中,SELECT FOR UPDATE獲取的是3級TM鎖。
1. SELECT * FROM TABLE1 FOR UPDATE 鎖定表的全部行,其它會話只能讀不能寫
2. SELECT * FROM TABLE1 WHERE PKID = 1 FOR UPDATE 只鎖定PKID=1的行
3. SELECT * FROM TABLE1 A JOIN TABLE2 B ON A.PKID=B.PKID FOR UPDATE 鎖定兩個表的全部記錄
4. SELECT * FROM TABLE1 A JOIN TABLE2 B ON A.PKID=B.PKID WHERE A.PKID = 10 FOR UPDATE 鎖定兩個表的中知足條件的行
5. SELECT * FROM TABLE1 A JOIN TABLE2 B ON A.PKID=B.PKID WHERE A.PKID = 10 FOR UPDATE OF A.PKID 只鎖定TABLE1中知足條件的行
FOR UPDATE 是把全部的表都鎖定。FOR UPDATE OF 根據OF後表的條件鎖定相對應的表。
摘抄自網絡,小麥苗感受本身對這個部分也沒啥可寫的,主要是包不能編譯的時候須要查詢DBA_DDL_LOCKS視圖,最後殺會話的時候須要穩重一點。
在數據庫的開發過程當中,常常碰到包、存儲過程、函數沒法編譯或編譯時會致使PL/SQL 沒法響應的問題。碰到這種問題,基本上都要重啓數據庫解決,嚴重浪費開發時間。本文將就產生這種現象的緣由和解決方案作基本的介紹。
問題分析
從事數據庫開發的都知道鎖的概念,如:執行 Update Table xxx Where xxx 的時候就會產生鎖。這種常見的鎖在Oracle裏面被稱爲DML鎖。在Oracle中還有一種DDL鎖,主要用來保證存儲過程、表結構、視圖、包等數據庫對象的完整性,這種鎖的信息能夠在DBA_DDL_LOCKS中查到。注意:V$LOCKED_OBJECT記錄的是DML鎖信息,DDL鎖的信息不在裏面。
對應DDL鎖的是DDL語句,DDL語句全稱數據定義語句(Data Define Language)。用於定義數據的結構或Schema,如:CREATE、ALTER、DROP、TRUNCATE、COMMENT、RENAME。當咱們在執行某個存儲過程、或者編譯它的時候Oracle會自動給這個對象加上DDL鎖,同時也會對這個存儲過程所引用的對象加鎖。
舉例:
一、 打開一個PL/SQL,開始調試某個函數(假設爲:FUN_CORE_SERVICECALL),並保持在調試狀態
二、 打開一個SQL Window,輸入Select * From dba_ddl_locks a Where a.name = 'FUN_CORE_SERVICECALL' 會發現一行記錄:
三、 打開一個新的PL/SQL,從新編譯這個函數。咱們會發現此時已經沒法響應了
四、 回到第一個PL/SQL,從新執行Select * From dba_ddl_locks a Where a.name = 'FUN_CORE_SERVICECALL' 咱們將會看到以下記錄:
五、 上述的狀況代表發生了鎖等待的狀況。
當咱們試圖編譯、修改存儲過程、函數、包等對數據對象的時候,若是別人也正在編譯或修改他們時就會產生鎖等待;或者咱們在編譯某個存儲過程的時候,若是它所引用的數據庫對象正在被修改應該也會產生鎖等待。這種假設有興趣的兄弟能夠測試下,不過比較困難。
解決方案
碰到這種問題,若是知道是被誰鎖定了(能夠查出來的),可讓對方儘快把鎖釋放掉;實在查不出來只能手工將這個鎖殺掉了。步驟以下:
一、 首先查出哪些進程鎖住了這個對象,語句以下:
Select b.SID,b.SERIAL#
From dba_ddl_locks a, v$session b
Where a.session_id = b.SID
And a.name = 'FUN_CORE_SERVICECALL';
二、 執行以下語句殺進程:alter system kill session 'sid,serial#' IMMEDIATE;
三、 執行了以上的語句後,有的時候不必定可以將進程殺掉。這個時候就須要連到數據庫服務器上殺掉服務器端的進程了,查詢語句:
Select spid, osuser, s.program
From v$session s, v$process p
Where s.paddr = p.addr
And s.sid =(上面查出來的SID)
在服務器上執行以下語句:
#kill -9 spid(UNIX平臺)
orakill sid thread(Windows平臺 SID是Oracle的實例名,thread是上面查出來的SID)
執行完4步之後基本上就能夠殺掉這些鎖死的進程了,不放心的話能夠再執行第一步確認下。
SQL> select distinct sid from v$mystat;
SID ---------- 24
SQL> CREATE OR REPLACE PROCEDURE PRO_TESTDDL_LHR AS 2 3 V_COUNT NUMBER; 4 5 BEGIN 6 7 SELECT COUNT(1) INTO V_COUNT FROM SCOTT.EMP_LHR; 8 9 DBMS_LOCK.SLEEP(600); 10 11 END; 12 /
Procedure created.
SQL> exec PRO_TESTDDL_LHR;
====>>>>> 腳本在執行
|
查看DDL鎖:
SELECT * FROM DBA_DDL_LOCKS D WHERE D.SESSION_ID = 24;
SELECT *
FROM V$ACCESS A
WHERE A.SID = 24
AND A.OBJECT IN ('PRO_TESTDDL_LHR', 'EMP_LHR', 'DBMS_LOCK');
版本:11.2.0.3
首先建表T_INDEX_161113並插入不少數據 SYS@oratest S1> CREATE TABLE T_INDEX_161113 AS SELECT * FROM DBA_OBJECTS;
Table created.
SYS@oratest S1> INSERT INTO T_INDEX_161113 SELECT * FROM T_INDEX_161113;
75349 rows created.
SYS@oratest S1> INSERT INTO T_INDEX_161113 SELECT * FROM T_INDEX_161113;
150698 rows created.
SYS@oratest S1> INSERT INTO T_INDEX_161113 SELECT * FROM T_INDEX_161113;
301396 rows created.
SYS@oratest S1> INSERT INTO T_INDEX_161113 SELECT * FROM T_INDEX_161113;
602792 rows created.
SYS@oratest S1> COMMIT;
Commit complete. 接着再在該表上建立一個索引 SYS@oratest S1> CREATE INDEX IDX_TEST_LHR ON T_INDEX_161113(OBJECT_NAME);
在建立索引的同時,在會話2上插入一條記錄: SYS@oratest S2> INSERT INTO T_INDEX_161113 SELECT * FROM T_INDEX_161113 WHERE ROWNUM<=1;
====>>>>> 產生了阻塞 在建立索引的同時,查詢相關鎖的信息: SQL> SELECT SID, 2 A.BLOCKING_SESSION, 3 EVENT, 4 A.P1, 5 A.P2, 6 A.P3, 7 CHR(BITAND(P1, -16777216) / 16777215) || 8 CHR(BITAND(P1, 16711680) / 65535) "LOCK", 9 BITAND(P1, 65535) "MODE", 10 (SELECT OBJECT_NAME FROM DBA_OBJECTS D WHERE D.OBJECT_ID = A.P2) OBJECT_NAME 11 FROM GV$SESSION A 12 WHERE A.SID=141;
SID BLOCKING_SESSION EVENT P1 P2 P3 LOCK MODE OBJECT_NAME ---------- ---------------- ----------------------- ---------- ---------- ---------- ---- ---------- ---------------- 142 21 enq: TM - contention 1414332419 77629 0 TM 3 T_INDEX_161113
SQL> SELECT * FROM V$LOCK A WHERE A.SID IN (21,142) AND A.TYPE IN ('TX','TM'); ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 00007F44001842E0 00007F4400184340 142 TM 77629 0 0 3 2 0 00007F44001842E0 00007F4400184340 21 TM 77629 0 4 0 3 1 00007F44001842E0 00007F4400184340 21 TM 18 0 3 0 3 0 0000000076273C58 0000000076273CD0 21 TX 65567 846 6 0 3 0
SQL> SELECT * FROM DBA_DML_LOCKS D WHERE D.SESSION_ID IN (21, 142); SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS ---------- --------- -------------------- ------------- ------------- ------------ -------------------- 142 SYS T_INDEX_161113 None Row-X (SX) 2 Not Blocking 21 SYS T_INDEX_161113 Share None 3 Blocking 21 SYS OBJ$ Row-X (SX) None 3 Not Blocking
SQL> SELECT D.OWNER, D.OBJECT_NAME, D.OBJECT_ID, D.OBJECT_TYPE 2 FROM DBA_OBJECTS D 3 WHERE D.OBJECT_ID IN (18, 77629);
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE ---------- ---------------------- ---------- ------------------- SYS T_INDEX_161113 77629 TABLE SYS OBJ$ 18 TABLE SQL> SELECT * FROM DBA_DDL_LOCKS D WHERE D.SESSION_ID IN (21, 142) AND D.name NOT IN ('STANDARD','DICTIONARY_OBJ_OWNER','DICTIONARY_OBJ_NAME','UTL_RAW','DBMS_APPLICATION_INFO','SDO_GEOR_DEF','SQL_TXT','DBMS_ASSERT','SDO_GEOR_DEF','TRACE_PUT_LINE','PLITBLM','DICTIONARY_OBJ_TYPE','DDLREPLICATION','DBMS_STANDARD','DBMS_APPLICATION_INFO','UTL_FILE','DDLAUX','DBMS_ASSERT','STANDARD','UTL_RAW','DDLREPLICATION','UTL_FILE','DDLAUX','GGS_MARKER_SEQ','DATABASE','LOGIN_USER','FILTERDDL','DBMS_UTILITY','GGS_DDL_SEQ','SYSEVENT','DBMS_UTILITY','LOGIN_USER','UTL_FILE','DATABASE','SDO_GEOR_DEF','UTL_RAW','GGS_DDL_SEQ','SDO_GEOR_DEF','DICTIONARY_OBJ_TYPE','UTL_RAW','DDLREPLICATION','DBMS_UTILITY','SYSEVENT','IS_VPD_ENABLED','DBMS_APPLICATION_INFO','FILTERDDL','DDLREPLICATION','STANDARD','DDLAUX','GGS_MARKER_SEQ','DDLAUX','SQL_TXT','PLITBLM','AW_DROP_PROC','DBMS_APPLICATION_INFO','DBMS_UTILITY','DICTIONARY_OBJ_OWNER','DICTIONARY_OBJ_NAME','STANDARD','DBMS_STANDARD','TRACE_PUT_LINE','UTL_FILE'); |