导致死锁的SQL示例

首先感谢: leonarding的文章,还有 晨_chen。

死锁定义:

从广义上讲包括操作系统 应用程序 数据库,如果2个进程(会话)相互持有对方的资源,都一直等待对方释放,这种情况会造成死锁。
误解:会话的阻塞不是死锁,因为其中有一个会话还是可以继续操作的。
释放:Oracle会自动检测死锁并强制干预释放-只释放了死锁的第一个,另一个还在HANG住。

1.需要创建一个表,用主键或惟一约束
BYS@ bys001>create table test(id varchar2(10) constraint pk__test_id primary key);

Table created.
BYS@ bys001>desc test;
Name                                                  Null?    Type
----------------------------------------------------- -------- ------------------------------------
ID                                                    NOT NULL VARCHAR2(10)

2.在会话38执行插入操作,值1.
BYS@ bys001>set time on
17:43:47 BYS@ bys001>select distinct sid from v$mystat;

       SID
----------
        38

17:47:13 BYS@ bys001>select * from test;

no rows selected
17:48:49 BYS@ bys001>insert into test values(1);

1 row created.
此时没有阻塞,可以查询到38号会话持有了一个模式3的TM表锁,
因为事务未提交,还持有模式6的事务锁
17:50:12 BYS@ bys001> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;


       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        38 TM      76864          0          3         0   0
        38 TX     262157      27843          6         0   0
17:54:07 BYS@ bys001>select object_name from dba_objects where object_id=76864;

OBJECT_NAME
----------------------------------------------------------------------------------------------------
TEST

3.在会话39插入值2

17:49:46 BYS@ bys001>select distinct sid from v$mystat;

       SID
----------
        39
17:51:07 BYS@ bys001>insert into test values(2);

1 row created.
此时可以查询到每个会话都产生的有两个锁定, BLOCK列全为0,此时没有阻塞。
17:51:25 BYS@ bys001> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;

       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        38 TM      76864          0          3         0   0
        38 TX     262157      27843          6         0   0    -----会话38有排他锁未阻塞会话
        39 TM      76864          0          3         0   0
        39 TX     327692      28225          6         0   0--------会话39有排他锁未阻塞会话


4.在会话39插入,值1,此时hang住
17:51:10 BYS@ bys001>insert into test values(1);

在会话38进行查询数据库阻塞:
17:57:18 BYS@ bys001> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;

       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        38 TM      76864          0          3         0   0
        38 TX     262157      27843          6         0   1 ------ 会话38阻塞会话39,因为会话38未提交,处于未决状态。
        39 TM      76864          0          3         0   0
        39 TX     262157      27843          0         4   0---------- 违反主键约束产生的阻塞,所以申请的是4级锁而非6级。
        39 TX     327692      28225          6         0   0


5.在会话38插入,值2,hang住,死锁产生

此时死锁被系统检测到,会话39插入值1的操作被释放--这个操作在会话38插入值2之前,但是会话38的锁定还在,需要手工释放。
也说明死锁被系统检测到后,ORACLE会回滚第一个,第二个仍在HANG住,需要手工回滚或提交来解决。
17:51:10 BYS@ bys001>insert into test values(1);
insert into test values(1)
            *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource


此时的会话38的插入操作是HANG住


数据库的锁定情况如下:
18:02:40 BYS@ bys001> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;

       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        38 TM      76864          0          3          0          0
        38 TX     327692      28225          0          4          0 ---- 违反主键约束产生的阻塞,所以申请的是4级锁而非6级。
        38 TX     262157      27843          6          0          0
        39 TM      76864          0          3          0          0
        39 TX     327692      28225          6          0          1     -------- 会话39阻塞会话38,因为会话38事务未提交,处于未决状态。

6.手动解决38号会话的HANG住问题:
在会话39上提交
18:09:36 BYS@ bys001>commit;

Commit complete.
会话38的HANG住解决,报错如下:
18:08:09 BYS@ bys001>insert into test values(2);
insert into test values(2)
*
ERROR at line 1:
ORA-00001: unique constraint (BYS.PK__TEST_ID) violated
还可以直接在38号上CTRL+C取消语句的执行。

LOCK作用:独占业务资源  保证读一致性  维护事务完整性
LOCK宗旨:没有并发就没有锁,一个人操作数据库是不会产生锁的

你可能感兴趣的:(ORACLE,事务)