oracle之報錯:ORA-00054: 資源正忙,要求指定 NOWAIT數據庫
問題以下:安全
SQL> conn scott/tiger@vm_database
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0
Connected as scottsession
。。。。。。併發
SQL> drop table student2;oracle
drop table student2app
ORA-00054: 資源正忙, 但指定以 NOWAIT 方式獲取資源, 或者超時失效
=========================================================ide
解決方法以下:ui
=========================================================spa
SQL> select session_id from v$locked_object;設計
SESSION_ID
----------
142
SQL> SELECT sid, serial#, username, osuser FROM v$session where sid = 142;
SID SERIAL# USERNAME OSUSER
---------- ---------- ------------------------------ ------------------------------
142 38 SCOTT LILWEN
SQL> ALTER SYSTEM KILL SESSION '142,38';
System altered
SQL> conn scott/tiger@vm_database
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0
Connected as scott
SQL> drop table student2;
Table dropped
Oracle數據庫的鎖類型
根據保護的對象不一樣,Oracle數據庫鎖能夠分爲如下幾大類:DML鎖(data locks,數據鎖),用於保護數據的完整性;DDL鎖(dictionary locks,字典鎖),用於保護數據庫對象的結構,如表、索引等的結構定義;內部鎖和閂(internal locks and latches),保護數據庫的內部結構。
DML鎖的目的在於保證併發狀況下的數據完整性,。在Oracle數據庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱爲表級鎖,TX鎖稱爲事務鎖或行級鎖。
當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的錯誤。這些現象都會對實際應用產生極大的危害,如長時間未響應,大量事務失敗等。
悲觀封鎖和樂觀封鎖
1、悲觀封鎖
鎖在用戶修改以前就發揮做用:
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.
2、樂觀封鎖
樂觀的認爲數據在select出來到update進取並提交的這段時間數據不會被更改。這裏面有一種潛在的危險就是因爲被選出的結果集並無被鎖定,是存在一種可能被其餘用戶更改的可能。所以Oracle仍然建議是用悲觀封鎖,由於這樣會更安全。
阻塞
定義:
當一個會話保持另外一個會話正在請求的資源上的鎖定時,就會發生阻塞。被阻塞的會話將一直掛起,直到持有鎖的會話放棄鎖定的資源爲止。4個常見的dml語句會產生阻塞
INSERT
UPDATE
DELETE
SELECT…FOR UPDATE
INSERT
Insert發生阻塞的惟一狀況就是用戶擁有一個建有主鍵約束的表。當2個的會話同時試圖向表中插入相同的數據時,其中的一個會話將被阻塞,直到另一個會話提交或會滾。一個會話提交時,另外一個會話將收到主鍵重複的錯誤。回滾時,被阻塞的會話將繼續執行。
UPDATE 和DELETE當執行Update和delete操做的數據行已經被另外的會話鎖定時,將會發生阻塞,直到另外一個會話提交或會滾。
Select …for update
當一個用戶發出select..for update的錯做準備對返回的結果集進行修改時,若是結果集已經被另外一個會話鎖定,就是發生阻塞。須要等另外一個會話結束以後纔可繼續執行。能夠經過發出 select… for update nowait的語句來避免發生阻塞,若是資源已經被另外一個會話鎖定,則會返回如下錯誤:Ora-00054:resource busy and acquire with nowait specified.
死鎖-deadlock
定義:當兩個用戶但願持有對方的資源時就會發生死鎖.
即兩個用戶互相等待對方釋放資源時,oracle認定爲產生了死鎖,在這種狀況下,將以犧牲一個用戶做爲代價,另外一個用戶繼續執行,犧牲的用戶的事務將回滾.
例子:
1:用戶1對A表進行Update,沒有提交。
2:用戶2對B表進行Update,沒有提交。
此時雙反不存在資源共享的問題。
3:若是用戶2此時對A表做update,則會發生阻塞,須要等到用戶一的事物結束。
4:若是此時用戶1又對B表做update,則產生死鎖。此時Oracle會選擇其中一個用戶進行會滾,使另外一個用戶繼續執行操做。
原由:
Oracle的死鎖問題實際上不多見,若是發生,基本上都是不正確的程序設計形成的,通過調整後,基本上都會避免死鎖的發生。
DML鎖分類表
表1 Oracle的TM鎖類型
鎖模式 鎖描述 解釋 SQL操做
0 none
1 NULL 空 Select
2 SS(Row-S) 行級共享鎖,其餘對象只能查詢這些數據行 Select for update、Lock for update、Lock row share
3 SX(Row-X) 行級排它鎖,在提交前不容許作DML操做 Insert、Update、Delete、Lock row share
4 S(Share) 共享鎖 Create index、Lock share
5 SSX(S/Row-X) 共享行級排它鎖 Lock share row exclusive
6 X(Exclusive) 排它鎖 Alter table、Drop able、Drop index、Truncate table 、Lock exclusive
1.關於V$lock表和相關視圖的說明
Column Datatype Description
ADDR RAW(4 | 8) Address of lock state object
KADDR RAW(4 | 8) Address of lock
SID NUMBER Identifier for session holding or acquiring the lock
TYPE VARCHAR2(2) Type of user or system lock
The locks on the user types are obtained by user applications. Any process that is blocking others is likely to be holding one of these locks. The user type locks are:
TM - DML enqueue
TX - Transaction enqueue
UL - User supplied
--咱們主要關注TX和TM兩種類型的鎖
--UL鎖用戶本身定義的,通常不多會定義,基本不用關注
--其它均爲系統鎖,會很快自動釋放,不用關注
ID1 NUMBER Lock identifier #1 (depends on type)
ID2 NUMBER Lock identifier #2 (depends on type)
---當lock type 爲TM時,id1爲DML-locked object的object_id
---當lock type 爲TX時,id1爲usn+slot,而id2爲seq。
--當lock type爲其它時,不用關注
LMODE NUMBER Lock mode in which the session holds the lock:
0 - none
1 - null (NULL)
2 - row-S (SS)
3 - row-X (SX)
4 - share (S)
5 - S/Row-X (SSX)
6 - exclusive (X)
--大於0時表示當前會話以某種模式佔有該鎖,等於0時表示當前會話正在等待該鎖資源,即表示該會話被阻塞。
--每每在發生TX鎖時,伴隨着TM鎖,好比一個sid=9會話擁有一個TM鎖,通常會擁有一個或幾個TX鎖,但他們的id1和id2是不一樣的,請注意
REQUEST NUMBER Lock mode in which the process requests the lock:
0 - none
1 - null (NULL)
2 - row-S (SS)
3 - row-X (SX)
4 - share (S)
5 - S/Row-X (SSX)
6 - exclusive (X)
--大於0時,表示當前會話被阻塞,其它會話佔有改鎖的模式
CTIME NUMBER Time since current mode was granted
BLOCK NUMBER The lock is blocking another lock
0, 'Not Blocking',
1, 'Blocking',
2, 'Global',
--該鎖是否阻塞了另一個鎖
2.其它相關視圖說明
視圖名 描述 主要字段說明
v$session 查詢會話的信息和鎖的信息。 sid,serial#:表示會話信息。
program:表示會話的應用程序信息。
row_wait_obj#:表示等待的對象,和dba_objects中的object_id相對應。
lockwait :該會話等待的鎖的地址,與v$lock的kaddr對應.
v$session_wait 查詢等待的會話信息。 sid:表示持有鎖的會話信息。
Seconds_in_wait:表示等待持續的時間信息
Event:表示會話等待的事件,鎖等於enqueue
dba_locks 對v$lock的格式化視圖。 Session_id:和v$lock中的Sid對應。
Lock_type:和v$lock中的type對應。
Lock_ID1: 和v$lock中的ID1對應。
Mode_held,mode_requested:和v$lock中
的lmode,request相對應。
v$locked_object 只包含DML的鎖信息,包括回滾段和會話信息。 Xidusn,xidslot,xidsqn:表示回滾段信息。和
v$transaction相關聯。
Object_id:表示被鎖對象標識。
Session_id:表示持有鎖的會話信息。
Locked_mode:表示會話等待的鎖模式的信
息,和v$lock中的lmode一致。
1.查詢數據庫中的鎖
select * from v$lock;
select * from v$lock where block=1;
2.查詢被鎖的對象
select * from v$locked_object;
3.查詢阻塞
查被阻塞的會話
select * from v$lock where lmode=0 and type in ('TM','TX');
查阻塞別的會話鎖
select * from v$lock where lmode>0 and type in ('TM','TX');
4.查詢數據庫正在等待鎖的進程
select * from v$session where lockwait is not null;
5.查詢會話之間鎖等待的關係
select a.sid holdsid,b.sid waitsid,a.type,a.id1,a.id2,a.ctime from v$lock a,v$lock b
where a.id1=b.id1 and a.id2=b.id2 and a.block=1 and b.block=0;
6.查詢鎖等待事件
select * from v$session_wait where event='enqueue';
解決方案:select session_id from v$locked_object; --首先獲得被鎖對象的session_idSELECT sid, serial#, username, osuser FROM v$session where sid = session_id; --經過上面獲得的session_id去取得v$session的sid和serial#,而後對該進程進行終止。ALTER SYSTEM KILL SESSION 'sid,serial';example:ALTER SYSTEM KILL SESSION '13, 8';