一、數(shù)據(jù)庫死鎖的現(xiàn)象
我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、疏勒ssl等。為數(shù)千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的疏勒網(wǎng)站制作公司
程序在執(zhí)行的過程中,點(diǎn)擊確定或保存按鈕,程序沒有響應(yīng),也沒有出現(xiàn)報錯。
二、oracle死鎖的原理
當(dāng)對于數(shù)據(jù)庫某個表的某一列做更新或刪除等操作,執(zhí)行完畢后該條語句不提交,另一條對于這一列數(shù)據(jù)做更新操作的語句在執(zhí)行的時候就會處于等待狀態(tài),此時的現(xiàn)象是這條語句一直在執(zhí)行,但一直沒有執(zhí)行成功,也沒有報錯。
三、oracle死鎖的定位方法
通過檢查數(shù)據(jù)庫表,能夠檢查出是哪一條語句被死鎖,產(chǎn)生死鎖的機(jī)器是哪一臺。
1)用dba用戶執(zhí)行以下語句
select username,lockwait,status,machine,program from v$session where sid in (select session_id from v$locked_object) 如果有輸出的結(jié)果,則說明有死鎖,且能看到死鎖的機(jī)器是哪一臺。字段說明:
Username:死鎖語句所用的數(shù)據(jù)庫用戶;
Lockwait:死鎖的狀態(tài),如果有內(nèi)容表示被死鎖。
Status: 狀態(tài),active表示被死鎖
Machine: 死鎖語句所在的機(jī)器。
Program: 產(chǎn)生死鎖的語句主要來自哪個應(yīng)用程序。
2)用dba用戶執(zhí)行以下語句,可以查看到被死鎖的語句。
Oracle數(shù)據(jù)庫出現(xiàn)死鎖的時候可以按照以下處理步驟加以解決:
第一步:嘗試在sqlplus中通過sql命令進(jìn)行刪除,如果能夠刪除成功,則萬事大吉!但通常情況下,出現(xiàn)死鎖時,想通過命令行或者通過Oracle的管理工具刪除有死鎖的session,oracle只會將該session標(biāo)記為killed,但無法清除掉,往往需要通過第二步在操作系統(tǒng)層級進(jìn)行刪除!
Connected?to?Oracle9i?Enterprise?Edition?Release?9.2.0.1.0?
Connected?as?quik
SQL?select?xidusn,?object_id,?session_id,?locked_mode?from?v$locked_object;?--查死鎖的對象,獲取其SESSION_ID
XIDUSN?OBJECT_ID?SESSION_ID?LOCKED_MODE
----------?----------?----------?-----------
10?30724?29?3
10?30649?29?3
SQL?select?username,sid,serial#?from?v$session?where?sid=29;?--根據(jù)上步獲取到的sid查看其serial#號
USERNAME?SID?SERIAL#
------------------------------?----------?----------
QUIK?29?57107
SQL?alter?system?kill?session?'29,57107';?--刪除進(jìn)程,如已經(jīng)刪除過,則會報ora-00031的錯誤;否則oracle會將該session標(biāo)記為killed狀態(tài),等待一段時間看能否會自動消失,如長時間消失不掉,則需要做后續(xù)步驟
alter?system?kill?session?'29,57107'
ORA-00031:?session?marked?for?kill
SQL?select?pro.spid?from?v$session?ses,v$process?pro?where?ses.sid=29?and?ses.paddr=pro.addr;?--查看spid號,以便在操作系統(tǒng)中根據(jù)該進(jìn)程號刪除進(jìn)程
SPID
------------
2273286
第二步:進(jìn)入操作系統(tǒng)進(jìn)行刪除進(jìn)程,本示例的操作系統(tǒng)是IBM aix。
login:?root?--錄入用戶名
root's?Password:?--錄入密碼
*******************************************************************************
*?*
*?*
*?Welcome?to?AIX?Version?5.3!?*
*?*
*?*
*?Please?see?the?README?file?in?/usr/lpp/bos?for?information?pertinent?to?*
*?this?release?of?the?AIX?Operating?System.?*
*?*
*?*
*******************************************************************************
Last?unsuccessful?login:?Fri?Apr?23?14:42:57?BEIDT?2010?on?/dev/pts/1?from?10.73
.52.254
Last?login:?Fri?Apr?23?15:27:50?BEIDT?2010?on?/dev/pts/2?from?10.73.52.254
#?ps?-ef|grep?2273286?--查看進(jìn)程詳情
root?2289864?2494636?0?17:07:15?pts/1?0:00?grep?2273286
oracle?2273286?1?0?14:38:24?-?0:21?oracleQUIK?(LOCAL=NO)
#?kill?-9?2273286?--刪除進(jìn)程,小心操作,別寫錯進(jìn)程號,如果oracle的關(guān)鍵進(jìn)程被刪,數(shù)據(jù)庫會崩潰的!
#?ps?-ef|grep?2273286?--再次查看
root?2289864?2494636?0?17:07:15?pts/1?0:00?grep?2273286
For?Windows,?at?the?DOS?Prompt:?orakill?sid?spid
For?UNIX?at?the?command?line?kill?–9?spid
你這里應(yīng)該存在兩個代碼對兩個表都有操作的過程,其中的一個表從你提供的日志上看應(yīng)該是t_user。
session 530 對應(yīng)的程序中肯定是 先執(zhí)行了類似于:SELECT * FROM TABLE1 FOR UPDATE,然后,在這個語句后面,執(zhí)行delete from t_user where ID=:1
語句
而你的Session 527則很有可能是執(zhí)行了類似于SELECT * FROM t_user FOR UPDATE, 然后,在這個語句之后,執(zhí)行對TABLE1的相關(guān)修改工作,從而造成表的死鎖問題。
具體的需要根據(jù)應(yīng)用來查詢,你可以看看相關(guān)的日志內(nèi)容。
首先你要知道表鎖住了是不是正常鎖?因為任何DML語句都會對表加鎖。
你要先查一下是那個會話那個sql鎖住了表,有可能這是正常業(yè)務(wù)需求,不建議隨便KILL
session,如果這個鎖表是正常業(yè)務(wù)你把session
kill掉了會影響業(yè)務(wù)的。
建議先查原因再做決定。
(1)鎖表查詢的代碼有以下的形式:
select
count(*)
from
v$locked_object;
select
*
from
v$locked_object;
(2)查看哪個表被鎖
select
b.owner,b.object_name,a.session_id,a.locked_mode
from
v$locked_object
a,dba_objects
b
where
b.object_id
=
a.object_id;
(3)查看是哪個session引起的
select
b.username,b.sid,b.serial#,logon_time
from
v$locked_object
a,v$session
b
where
a.session_id
=
b.sid
order
by
b.logon_time;
(4)查看是哪個sql引起的
select
b.username,b.sid,b.serial#,c.*
from
v$locked_object
a,v$session
b,v$sql
c
where
a.session_id
=
b.sid
and
b.SQL_ID
=
c.sql_id
and
c.sql_id
=
''
order
by
b.logon_time;
(5)殺掉對應(yīng)進(jìn)程
執(zhí)行命令:alter
system
kill
session'1025,41';
其中1025為sid,41為serial#.
樓主您好
所謂的鎖等待:就是一個事務(wù)a對一個數(shù)據(jù)表進(jìn)行ddl或是dml操作時,系統(tǒng)就會對該表加上表級的排它鎖,此時其他的事務(wù)對該表進(jìn)行操作的時候會等待a提交或是回滾后,才可以繼續(xù)b的操作
所謂的死鎖:當(dāng)兩個或多個用戶相互等待鎖定的數(shù)據(jù)時就會發(fā)生死鎖,這時這些用戶被卡在不能繼續(xù)處理業(yè)務(wù),oracle可以自動檢測死鎖并解決他們,通過回滾一個死鎖中的語句,釋放鎖定的數(shù)據(jù),回滾的話會遇到ora-00060
deadlock detected while waiting for resource
模擬鎖等待:
兩個事務(wù)a和b,分別創(chuàng)建t1,t2,并且初始化一條數(shù)據(jù),
a 更改t1的數(shù)據(jù),此時并不提交,這時候b更改相同的一列,此時b一直處于等待的狀態(tài)
我們可以查詢鎖等待的內(nèi)容:
wait_lock.sql
select
(select username from v$session where sid = a.sid) username,
a.sid,
(select serial# from v$session where sid = a.sid) serial#,
a.type,
a.id1,
a.id2,
a.lmode,
a.request,
a.block,
b.sid blocking_sid
from v$lock a,
( select * from v$lock
where request 0
and type 'MR'
) b
where a.id1 = b.id1(+)
and a.id2 = b.id2(+)
and a.lmode 0
and a.type 'MR'
order by username,a.sid,serial#,a.type
此時可以查詢到鎖等待的現(xiàn)象,最后一列不為空的就是等待的事件
此時我們可以跟a用戶提示讓其提交事務(wù)或是回滾,也可以直接殺死
alter system kill session 'sid,serial#';
保持現(xiàn)狀不動,在a事務(wù)更改t2表此時在a事務(wù)會產(chǎn)生
SQL update t1 set id=1000 where id=1;
update t1 set id=1000 where id=1
*
第 1 行出現(xiàn)錯誤:
ORA-00060: 等待資源時檢測到死鎖
此時oracle已經(jīng)幫我解決了這個死鎖問題
死鎖的產(chǎn)生需要四個必須的條件:
1 ,mutual execution(互斥)資源不能被共享,只能由一個進(jìn)程使用
2,hold and wait(請求并持續(xù))已經(jīng)得到資源的進(jìn)程可以再次申請新的資源
3,no pre-emption(不可剝奪)已經(jīng)分配的資源不能被相應(yīng)的進(jìn)程強(qiáng)制剝奪
4,circular wait(循環(huán)等待條件)系統(tǒng)中若干進(jìn)程組成環(huán)路,該環(huán)路中的每個進(jìn)程都在等待相鄰進(jìn)程正占用的資源
定位死鎖:
系統(tǒng)級別的定位
Select username,lockwait,status,machine,program from v$session where sid in (select session_id from v$locked_object)
Username死鎖的用戶,lockwait死鎖的狀態(tài),status中active表示死鎖,machine死鎖所在的機(jī)器,program死鎖來自于那個程序
語句級別的定位
Select sql_text from v$sql where hash_value in (select
sql_hash_value from v$session where sid in (select session_id from
v$locked_object));
進(jìn)程級別的定位
Select s.username,l.object_id,l.session_id,s.serial#,l.oracle_usrename,l.os_user_name,l.process from v$locked_object l,v$session s where l.session_id=s.sid;
處理死鎖的一般策略
1,鴕鳥算法忽略該問題
2,定位死鎖并且恢復(fù)
3,仔細(xì)對資源進(jìn)行動態(tài)分配,避免死鎖
4,破壞死鎖中的一個條件
如果oracle解決不了的死鎖,我們需要定位到進(jìn)程級別,找到對應(yīng)的sid和serial#
alter system kill 'sid,serail#'
失敗的話,找到對應(yīng)的進(jìn)程強(qiáng)制關(guān)閉
Select p.spid from v$session s, v$process p where s.sid=xx and s.paddr=p.addr
ps -ef | grep spid
kill -9 xx
查詢oracle的死鎖
lock.sql
SELECT bs.username "Blocking User", bs.username "DB User",
ws.username "Waiting User", bs.SID "SID", ws.SID "WSID",
bs.serial# "Serial#", bs.sql_address "address",
bs.sql_hash_value "Sql hash", bs.program "Blocking App",
ws.program "Waiting App", bs.machine "Blocking Machine",
ws.machine "Waiting Machine", bs.osuser "Blocking OS User",
ws.osuser "Waiting OS User", bs.serial# "Serial#",
ws.serial# "WSerial#",
DECODE (wk.TYPE,
'MR', 'Media Recovery',
'RT', 'Redo Thread',
'UN', 'USER Name',
'TX', 'Transaction',
'TM', 'DML',
'UL', 'PL/SQL USER LOCK',
'DX', 'Distributed Xaction',
'CF', 'Control FILE',
'IS', 'Instance State',
'FS', 'FILE SET',
'IR', 'Instance Recovery',
'ST', 'Disk SPACE Transaction',
'TS', 'Temp Segment',
'IV', 'Library Cache Invalidation',
'LS', 'LOG START OR Switch',
'RW', 'ROW Wait',
'SQ', 'Sequence Number',
'TE', 'Extend TABLE',
'TT', 'Temp TABLE',
wk.TYPE
) lock_type,
DECODE (hk.lmode,
0, 'None',
1, 'NULL',
2, 'ROW-S (SS)',
3, 'ROW-X (SX)',
4, 'SHARE',
5, 'S/ROW-X (SSX)',
6, 'EXCLUSIVE',
TO_CHAR (hk.lmode)
) mode_held,
DECODE (wk.request,
0, 'None',
1, 'NULL',
2, 'ROW-S (SS)',
3, 'ROW-X (SX)',
4, 'SHARE',
5, 'S/ROW-X (SSX)',
6, 'EXCLUSIVE',
TO_CHAR (wk.request)
) mode_requested,
TO_CHAR (hk.id1) lock_id1, TO_CHAR (hk.id2) lock_id2,
DECODE
(hk.BLOCK,
0, 'NOT Blocking', /**//* Not blocking any other processes */
1, 'Blocking', /**//* This lock blocks other processes */
2, 'Global', /**//* This lock is global, so we can't tell */
TO_CHAR (hk.BLOCK)
) blocking_others
FROM v$lock hk, v$session bs, v$lock wk, v$session ws
WHERE hk.BLOCK = 1
AND hk.lmode != 0
AND hk.lmode != 1
AND wk.request != 0
AND wk.TYPE(+) = hk.TYPE
AND wk.id1(+) = hk.id1
AND wk.id2(+) = hk.id2
AND hk.SID = bs.SID(+)
AND wk.SID = ws.SID(+)
AND (bs.username IS NOT NULL)
AND (bs.username 'SYSTEM')
AND (bs.username 'SYS')
ORDER BY 1;
這些語句的執(zhí)行最好是在plsql或是sqldeveloper如果是直接在數(shù)據(jù)庫里面執(zhí)行的需要格式化表,否則會很讓你眼花的。