如果有两个会话,每个会话都持有另一个会话想要的资源,此时就会发生死锁。
用下面实验来说明死锁的产生原因和解决办法。
SESSION1:
SQL> create table t2 as select * from emp;
SQL> select * from t2 where empno=7369;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 19801217 00:00:00 800 20
SQL> update t2 set sal=sal+200 where empno=7369;
SQL> select * from t2 where empno=7369;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 19801217 00:00:00 1000 20
SESSION2:
SQL> select * from t2 where empno=7900;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7900 JAMES CLERK 7698 19811203 00:00:00 950 30
SQL> update t2 set sal=sal+200 where empno=7900;
1 row updated.
SQL> select * from t2 where empno=7900;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7900 JAMES CLERK 7698 19811203 00:00:00 1150 30
SESSION1:
SQL> select * from t2 where empno=7900;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7900 JAMES CLERK 7698 19811203 00:00:00 950 30
SESSION2:
SQL> select * from t2 where empno=7369;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 19801217 00:00:00 800 20
SESSION1:
SQL> update t2 set sal=sal-200 where empno=7900;
出现等待
SESSION2:
SQL> update t2 set sal=sal-200 where empno=7369;
死锁发生,session2被阻塞
系统回滚session1跟死锁有关的sql。
update t2 set sal=sal-200 where empno=7900
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
SESSION1:
SQL> select * from t2 where empno in (7369,7900);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 19801217 00:00:00 1000 20
7900 JAMES CLERK 7698 19811203 00:00:00 950 30
看到系统只回滚了对empno=7900的修改。
而此时SESSION2的update t2 set sal=sal-200 where empno=7369;依然被SESSION1的第一条语句所阻塞。
我们现在查看产生锁的情况
打开第三个会话以DBA身份登录
SQL> select * from v$lock;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
29434224 29434238 165 XR 4 0 1 0 2998 0
29434280 29434294 165 CF 0 0 2 0 2988 0
294342DC 294342F0 167 PW 1 0 3 0 2980 0
29434338 2943434C 165 RS 25 1 2 0 2983 0
294343F0 29434404 166 RT 1 0 6 0 2983 0
2943444C 29434460 153 TX 589868 325 0 4 24 0
29434560 29434574 167 MR 1 0 4 0 2983 0
294345BC 294345D0 167 MR 2 0 4 0 2983 0
29434618 2943462C 167 MR 3 0 4 0 2983 0
29434674 29434688 167 MR 4 0 4 0 2983 0
294346D0 294346E4 167 MR 5 0 4 0 2983 0
2943472C 29434740 167 MR 6 0 4 0 2983 0
29434788 2943479C 167 MR 7 0 4 0 2983 0
294347E4 294347F8 167 MR 201 0 4 0 2983 0
2943489C 294348B0 164 TS 3 1 3 0 2979 0
288F6030 288F6048 144 TM 53257 0 3 0 51 0
288F60DC 288F60F4 153 TM 53257 0 3 0 24 0
28934170 28934194 153 TX 655363 241 6 0 24 0
28969404 28969428 144 TX 589868 325 6 0 51 1
19 rows selected.
用下面的SQL语句可以直接得出谁阻塞谁
SQL> select ( select username from v$session where sid=a.sid) blocker, a.sid,
‘ is blocking ‘,
(select username from v$session where sid=b.sid) blockee, b.sid
from v$lock a, v$lock b
where a.block=1 and b.request>0 and a.id1=b.id1 and a.id2=b.id2;
BLOCKER SID ‘ISBLOCKING‘ BLOCKEE SID
------------------------------ ---------- ------------- ------------------------------ ----------
STONE 144 is blocking STONE 153
发生死锁的时候会在alert文件里记录下信息。
--查看操作系统下$ORACLE_BASE/admin/orcl/bdump/alert_orcl.log文件,会找到如下信息
Thu Sep 2 20:41:25 2010
ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/orcl/udump/orcl_ora_4945.trc.
再查看跟踪文件详细信息
*** 2010-09-02 20:41:25.700
*** ACTION NAME () 2010-09-02 20:41:25.699
*** MODULE NAME (SQL*Plus) 2010-09-02 20:41:25.699
*** SERVICE NAME (SYS$USERS) 2010-09-02 20:41:25.699
*** SESSION ID (144.3) 2010-09-02 20:41:25.699
DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-00090015-00000146 19 144 X 23 148 X
.......
SESSION2还在被SESSION1阻塞,只有在SESSION1执行提交或回退才能让SESSION2继续下去。
SESSION1:
commit; --将提交update t2 set sal=sal+200 where empno=7369的修改
或
rollback;--将取消update t2 set sal=sal+200 where empno=7369的修改
随即SESSION2得到1 row updated.的信息。
我们也可以用管理员账号执行kill命令杀死导致阻塞的会话SESSION1来解决死锁。
sqlplus / as sysdba
从上面查过的信息可以知道产生阻塞的sid=144
通过查v$session视图可以得出serial#
SADDR SID SERIAL# AUDSID PADDR USER# USERNAME COMMAND OWNERID TADDR
-------- ---------- ---------- ---------- -------- ---------- ----------- ---------- ---------- -----
29F0BED4 144 3 210009 29E24174 64 STONE 0 2147483644
杀死这个会话用下面的命令
alter system kill session ‘144,3‘;
总结:
Oralce认为死锁是应用导致的错误,Oracle中很少出现死锁。导致死锁的的头号杀手是外键没有加索引,第二号杀手则是位图索引遭到并发更新。
如果外键没有索引,我们更新了父表的主键时将会锁住整个子表。如果外键没有索引,删除了父表中的一行,整个子表也会被锁住。这样就很容易产生很多问题,如果其中任何阻塞的会话锁住了某一会话需要的资源就会出现一个死锁。至于位图索引的并发更新,是会锁住所有相关联的行,也会导致问题的发生。
在Oracle9i及以上版本中,这些全表锁都是短期的,也就是仅在DML操作期间存在,而不是存在于整个事务期间。
本文转自:http://www.itpub.net/thread-1347577-1-1.html