Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2585444
  • 博文数量: 323
  • 博客积分: 10211
  • 博客等级: 上将
  • 技术积分: 4934
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-27 14:56
文章分类

全部博文(323)

文章存档

2012年(5)

2011年(3)

2010年(6)

2009年(140)

2008年(169)

分类: Oracle

2008-05-27 14:52:02

4.2    实体完整性引发的锁阻塞

DEPT(部门)表有如下字段DEPTNO(部门编号),DNAME(部门名称),LOC(部门位置);其中DEPTNO列为主键。

SESS#1

SQL> INSERT INTO DEPT(DEPTNO) VALUES(50);

1 row created.

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          7 Row Exclusive   DEPT                 6      88     29

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TX     393304         29 Exclusive                0          6          0

7 TM       3574          0 Row Exclusive            0          6          0

DEPT表中插入一条DEPTNO50的记录后,SESS#1SID7)在DEPT表上获得Row Exclusive锁,并且由于进行了数据插入,该事务被分配了回滚段,获得TX锁。

SESS#2

INSERT INTO DEPT(DEPTNO) VALUES(50);

这时,SESS#2SID8)也向DEPT表中插入一条DEPTNO50的记录,该语句被阻塞,检查锁情况:

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          8 Row Exclusive   DEPT                 7      75     30

SCOTT          7 Row Exclusive   DEPT                 6      88     29

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TX     393304         29 Exclusive                0         92          1

    7 TM       3574          0 Row Exclusive            0         92          0

    8 TX     458827         30 Exclusive                0         22          0

    8 TM       3574          0 Row Exclusive            0         22          0

8 TX     393304         29 None                     4         22          0

SESS#2DEPT表上也获得了Row Exclusive锁,同样也获得了回滚段的分配,得到TX锁,但是由于其插入的记录与SESS#1插入的记录的DEPTNO均为50,该语句成功与否取决于SESS#1的事务是提交还是回滚,所以SESS#2被阻塞,表现为SESS#2Share方式(REQUEST=4)等待SESS#1所持有的TX锁的释放。

这时,如果SESS#1进行回滚:

SESS#1

SQL> ROLLBACK;

Rollback complete.

SESS#2

1 row created.

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          8 Row Exclusive   DEPT                 7      75     30

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    8 TX     458827         30 Exclusive                0        136          0

    8 TM       3574          0 Row Exclusive            0        136          0

SESS#2的阻塞将被解除,SESS#2只持有原先已有的TMTX锁,其等待的TX锁(由SESS#1持有)也消失了。

如果SESS#1提交而不是回滚,在SESS#2上将会出现如下提示:

ERROR at line 1:

ORA-00001: unique constraint (SCOTT.PK_DEPT) violated错误。

即发生主键冲突,SESS#1SESS#2的所有锁资源均被释放。

4.3    参照完整性引发的锁阻塞

EMP(员工)表有如下字段:EMPNO(员工编号),ENAME(员工姓名),DEPTNO(员工所在部门编号),其中DEPTNO列为外键,其父表为DEPT

SESS#1

SQL> insert into dept(deptno) values(60);

1 row created.

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          7 Row Exclusive   DEPT                 2       6     33

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TX     131078         33 Exclusive                0        148          0

    7 TM       3574          0 Row Exclusive            0        148          0

SESS#1SID7)在DEPT表中先插入一条DEPTNO60的记录,SESS#1获得了DEPT表上的Row Exclusive锁,及一个TX锁。

SESS#2

insert into emp(empno,deptno) values(2000,60)

被阻塞

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          7 Row Exclusive   DEPT                 2       6     33

SCOTT          8 Row Exclusive   EMP                  3      20     31

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TX     131078         33 Exclusive                0        228          1

    7 TM       3574          0 Row Exclusive            0        228          0

    8 TX     196628         31 Exclusive                0          9          0

    8 TM       3576          0 Row Exclusive            0          9          0

    8 TX     131078         33 None                     4          9          0

SESS#2SID8)向EMP表中出入一条新记录,该记录DEPT值为60(即SESS#1刚插入,但还未提交的记录的DEPTNO值),SESS#2获得了EMP表上的Row Exclusive锁,另外由于插入记录,还分配了回滚段及一个TX锁,但由于SESS#2的插入语句是否成功取决于SESS#1的事务是否进行提交,所以它被阻塞,表现为SESS#2ShareREQUEST=4)方式等待SESS#1释放其持有的TX锁。这时SESS#1如果提交,SESS#2的插入也将执行成功,而如果SESS#1回滚,由于不符合参照完整性,SESS#2将报错:

SESS#2

insert into emp(empno,deptno) values(2000,60)

*

ERROR at line 1:

ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated - parent key not

Found

SESS#2持有的锁也被全部释放。

4.4    外键未加索引引发的锁阻塞

EMP表上的DEPTNO列为外键,但没有在该列上建索引。

SESS#1

SQL> delete emp where 0=1;

0 rows deleted.

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          7 Row Exclusive   EMP                  0       0      0

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

7 TM       3576          0 Row Exclusive            0         10          0

首先SESS#1SID7)做了一个删除操作,但由于条件(0=1)为永假,所以实际上并没有一行被删除,从监控脚本可以看出SESS#1EMP表上获得Row Exclusive锁,但由于没有实际的行被删除,所以并没有TX锁,也没有为SESS#1分配回滚段。

SESS#2

SQL> delete dept where 0=1;

该语句虽然也不会删除实际数据,但却被阻塞,查看系统的锁情况:

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          8 None            EMP                  0       0      0

SCOTT          7 Row Exclusive   EMP                  0       0      0

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TM       3576          0 Row Exclusive            0         31          1

    8 TM       3576          0 None                     4         12          0

SESS#2申请在EMP表上加SHARE锁(REQUEST=4),但该申请被SESS#1阻塞,因为SESS#1已经在EMP表上获得了Row Exclusive锁,与SHARE锁不相容。

下面我们对SESS#1进行回滚后,再进行监控。

SESS#3

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          8 Share           EMP                  0       0      0

SCOTT          8 Row Exclusive   DEPT                 0       0      0

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    8 TM       3574          0 Row Exclusive            0         16          0

8 TM       3576          0 Share                    0         16          0

SESS#2EMP表上获得Share锁后,又在DEPT表上获得Row Exclusive锁,由于没有实际的行被修改,SESS#2并没有获得TX锁。

Oracle8中,如果子表的外键上没有加索引,当在父表上删除记录时,会先在子表上申请获得Share锁,之后再在父表上申请Row Exclusive锁。由于表级Share锁的封锁粒度较大,所以容易引起阻塞,从而造成性能问题。

当在外键上建立索引后,在父表上删除数据将不再对子表上加Share锁,如下所示:

SESS#1

SQL> create index i_emp_deptno on emp(deptno);

Index created.

SQL> delete dept where 0=1;

0 rows deleted.

SQL>

SQL> @showlock

O_NAME       SID LOCK_TYPE       OBJECT_NAME     XIDUSN XIDSLOT XIDSQN

---------- ----- --------------- --------------- ------ ------- ------

SCOTT          7 Row Exclusive   DEPT                 0       0      0

SQL> @showalllock

  SID TY        ID1        ID2 LOCK_TYPE          REQUEST      CTIME      BLOCK

----- -- ---------- ---------- --------------- ---------- ---------- ----------

    7 TM       3574          0 Row Exclusive            0          9          0

可以看到,在EMPDEPTNO列上建立索引后,在DEPT表上执行DELETE操作,不再要求在EMP表上加Share锁,只是在DEPT表上加Row Exclusive锁,封锁的粒度减小,引起阻塞的可能性也减小。

5       Oracle 多粒度封锁机制总结

Oracle通过具有意向锁的多粒度封锁机制进行并发控制,保证数据的一致性。其DML锁(数据锁)分为两个层次(粒度):即表级和行级。通常的DML操作在表级获得的只是意向锁(RSRX),其真正的封锁粒度还是在行级;另外,在Oracle数据库中,单纯地读数据(SELECT)并不加锁,这些都极大地提高了系统的并发程度。

在支持高并发度的同时,Oracle利用意向锁及数据行上加锁标志位等设计技巧,减小了Oracle维护行级锁的开销,使其在数据库并发控制方面有着明显的优势。

 

 

最近,在Oracle专题深入讨论区,对我这篇文章进行了讨论,见http://www.itpub.net/270059.html
现在我想概括总结一下:
在Oracle数据库并发环境下,对于表,既要保护其数据,又要保护其结构(结构信息存储在数据字典中),很自然,针对这两种保护要求,就有了两种类型(Type)的锁:保护数据的锁我们叫数据锁(DML locks或data locks),保护结构的我们叫字典锁(DDL locks或dictionary locks)。

对于数据锁,为了适应不同事务的不同要求,提供两个层次(粒度)的锁,即表级锁(Table Locks ,TM)与行级锁(Row Locks ,TX)。
在这两个层次上,经典的上锁的方式(Mode)有两种,即共享锁(S锁)与排它锁(X锁)。

为了方便地进行锁冲突的检测,希望在表(上)级能够标识行(下)级加锁的情况,这就引入了“意向锁”(intention lock mode)的概念。根据在行级要加S锁或X锁的不同,在表级相应的就有两种意向锁,即:如果事务要在行级获得S锁,它需要首先在表级获得意向共享锁(Intent Share Lock,IS锁);如果事务要在行级获得X锁,它需要首先在表级获得意向排它锁(Intent Exclusive Lock,IX锁)。这两种意向锁与经典的S锁、X锁组合,还会产生一种新的锁:共享意向排它锁(Share Intent Exclusive Lock,SIX锁),它表示持有该锁的事务在表级加了传统的共享锁(S锁),同时该事务还将对表中的某些行加排它锁(X锁)。

这样,在表级数据锁的加锁方式就有了5种:即S、X、IS、IX、SIX。
在Oracle中,与IS对应的锁叫做Row Share Table Locks (RS)或subshare table lock, SS,它可以通过SELECT ... FOR UPDATE语句获得,但需要注意的是,这个语句在行级获得的也是排它锁,即如果两个SELECT ... FOR UPDATE语句要选定同一行,则后面的事务将被阻塞,这是与上面一般意义的定义有所不同,这时RS锁可以理解为持有该锁的事务将要修改选定的某些行。

在Oracle中,与IX对应的锁叫做Row Exclusive Table Locks (RX)或subexclusive table lock, SX,它可以通过INSERT/UPDATE/DELETE语句获得,它表征持有该锁的事务已经修改了表中的某些行。

在Oracle中,与SIX对应的锁叫做Share Row Exclusive Table Locks (SRX)或sshare-subexclusive table lock, SSX。

这样,Oracle对表级数据锁的加锁方式就有:即S、X、RS、RX、SRX等5种;而在行级只有X锁。

在Oracle中,对于字典锁,也有共享与排它之分:Share DDL Locks与Exclusive DDL Locks。对于要获得Exclusive DDL Locks的DDL操作(如ALTER、DROP等),它还必须要获得该表排它的数据锁,这样如果在某个表上有未提交的事务(即该表有某种类型的表级锁),其它SESSION提出的DROP表的操作就不会成功,因为它要向表施加X锁,与表上已有的锁不相容。
所以说,表级的数据锁既能防止与之冲突的DML操作,也能防止与之冲突的DDL操作,但不能因此就把表级的数据锁与字典锁混为一谈。

阅读(1311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~