数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

解析Oracle多粒度锁的验证步骤


发布日期:2022年03月29日
 
解析Oracle多粒度锁的验证步骤

创建测试表

create>aaa@AAAUSORACLECOM>create table test (a numberb number)

表已创建

对于未提交的insert操作

insert>aaa@AAAUSORACLECOM>insert into test values(

已创建

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

ABABATM

AFAFTX

可见对于未提交的insert操作会产生两个锁其类型(TYPE)分别为TM和TX也就是表级意向锁和事务锁

表级意向锁的模式(LMODE)为表示是row exclusive即表示此表中的某行获得了行排他锁

事务锁的模式(LMODE)为 表示是exclusive即排他锁表示此事务获得了排他锁

BLOCK表示此锁是否阻塞了其它的锁即发生死锁此处没有

对于提交的insert操作

commit>aaa@AAAUSORACLECOM>commit

提交完成

cellPadding= width=% bgColor=#cccccc>ff>

SQL> select * from v$lock;

ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK

此处已没有记录说明在提交后即完成了锁的释放

对于未提交的update操作

update>aaa@AAAUSORACLECOM>update test set a= where a=

已更新

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

ABABATM

AFAFTX

可见update操作所引起的锁的信息完全等同于insert操作……

对于提交的update操作

commit>aaa@AAAUSORACLECOM>commit

提交完成

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

此处已没有记录说明在提交后即完成了锁的释放

对于select操作

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>select*fromtestwherea=;

AB

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

此处已没有记录说明select操作不会引起任何锁

这是与sql server等数据库不同的这些数据库select操作也会引起锁以取得一致读

而oracle是通过回滚机制实现一致读的所以不需要引入锁机制这极大增强了oracle的并发度

for update操作

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>select*fromtestforupdate;

AB

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

ABABATM

AFAFTX

可见for update操作会引起两个锁分别是表级意向锁(TM)和事务锁(TX)

表级意向锁锁定模式为(row share)这表示属于此表中的某行获得了共享锁相比较DML操作此处锁级别低了一级DML的是其实在oracle中没有行级共享锁

TX的锁定模式为表示行级排他锁这与DML的效果一致

for update操作commit后

当commit后就会发现锁已被释放

for update与update互锁问题

) session

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>select*fromtestforupdate;

AB

) session

update>aaa@AAAUSORACLECOM>update test set a= where a=

此时这条语句处于阻塞状态说明等待锁

查看锁

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

DCCCDCDCTX

ABABCTM

ABABATM

AFAFTX

发现有两个会话处于有锁的活动

发出for update操作的session (sid=)的有模式为(row share)的行级共享意向表级锁模式为(exclusive)行级排他锁

发出update操作的session (sid=)的模式为(row exclusive)的行级排他意向锁模式为(None)的行级锁

这说明第二个session(sid=)由于是后发出的操作它会首先去检索将要操作的表是否存在锁此处由于存在故就堵塞了所以没有获得行级锁

这也就说两个session在检测操作对象是否处于被锁状态时是首先检测其表级锁这就避免了去检测没一行的锁这就提升了性能

像这里的情况我们所操作的对象是行但所利用的检测锁机制是在表级

同时会发现session (sid=)的TX锁的BLOCK为这表示此锁堵住了另外的锁同时我们会看到session (sid=)的TX锁等待的对象ID和ID与sid=的相同这说明sid=的堵住了sid=

rollback第一个会话的for update操作

rollback>aaa@AAAUSORACLECOM>rollback

回退已完成

查看锁

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

ABABCTM

AEBAEBCTX

可见第一锁的信息已没有

此时只有session 的锁的信息而且session 已获得锁

如果再将session 进行回滚就会发现session 的锁也没有了

实体完整性引发的锁阻塞

在具有primary key约束的表中在两个session中插入同样的记录

alter>aaa@AAAUSORACLECOM>alter table test add constraint pk_a primary key(a)

表已更改

Session

insert>aaa@AAAUSORACLECOM>insert into test(a) values(

已创建

Session

insert>aaa@AAAUSORACLECOM>insert into test(a) values(

session 处于阻塞状态

可见在session没有提交的情况实体完整性约束就会阻塞住session

查看锁

cellPadding= width=% bgColor=#cccccc>ff>

SQL>select*fromv$lock;

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

DCCCDCDCTX

AEBAEBCTX

ABABCTM

ABABATM

AECAEATX

可见session (sid=)已获得TM和TX锁并且阻塞住了其它的锁

session (sid=)被阻塞

可以发现 session 已获得了行排他锁

AEB AEBC TX

已经完全分配了新的事务所以session 不是被堵在和session 竞争同一个数据块上(如上面的例子)而是被堵在了完整行约束上

DCCC DCDC TX

这个锁请求的类型为 (share)

Sessio

rollback>aaa@AAAUSORACLECOM>rollback

回退已完成

Session

insert>aaa@AAAUSORACLECOM>insert into test(a) values(

已创建

cellPadding= width=% bgColor=#cccccc>ff>

ADDRKADDRSIDTYPEIDDLMODEREQUESTCTIMEBLOCK

ABABCTM

AEBAEBCTX

可见session 所持有的锁剩余两个那个原来等待session 的锁已释放

参照完整性引发的锁阻塞

create>aaa@AAAUSORACLECOM>create table test_child(c numbera number not null constra

int pk_a_ref references test(a))

表已创建

insert>aaa@AAAUSORACLECOM>insert into test(a) values(

已创建

Session

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowExclusiveTEST

AAARowshareTEST_CHILD

可以发现有两个对象被锁住 TEST和TEST_CHILD

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TMRowExclusive

TMRowshare

TXExclusive

可见有三个锁

cellPadding= width=% bgColor=#cccccc>ff>

SQL>selectobject_namefromdba_objectswhereobject_id=;

OBJECT_NAME

TEST

SQL>selectobject_namefromdba_objectswhereobject_id=;

OBJECT_NAME

TEST_CHILD

可见除了TEST表需要的TM和TX锁外

还同时将TEST_CHILD表锁住了其锁类型为Row share

session

insert>aaa@AAAUSORACLECOM>insert into test_child(ca) values(

插入外键值为语句的执行会停顿

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowshareTEST

AAARowExclusiveTEST_CHILD

AAARowExclusiveTEST

AAARowshareTEST_CHILD

这时会发现被锁住的对象有这是因为在子表中的插入同时会锁住父表和子表

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TXNone

TMRowshare

TMRowExclusive

TXExclusive

TMRowExclusive

TXExclusive

TMRowshare

已选择

分析锁的情况

Session (sid=)有四个锁分别是子表的TM和TX锁

TM Row Exclusive

TX Exclusive

父表的TM和TX锁

TX None

TM Row share

这是因为参照完整性需要父表在参照的过程中不能发生改变所以要对父表加上这些限制

Session

rollback>aaa@AAAUSORACLECOM>rollback

回退已完成

Session

insert>aaa@AAAUSORACLECOM>insert into test_child(ca) values(

insert into test_child(ca) values(

*

ERROR 位于第

ORA 违反完整约束条件 (AAAPK_A_REF) 未找到父项关键字

更新子表时

update>aaa@AAAUSORACLECOM>update test_child set a= where =

已更新

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowshareTEST

AAARowExclusiveTEST_CHILD

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TMRowshare

TMRowExclusive

可见当更新子表时会锁住父子两个表即使实际上没有更新数据

当更新父表时

update>aaa@AAAUSORACLECOM>update test set a= where =

已更新

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowExclusiveTEST

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TMRowExclusive

>

可见更新父表只会锁住父表

当父子两个表同时更新时

session

update>aaa@AAAUSORACLECOM>update test_child set a= where =

已更新

Session

update>aaa@AAAUSORACLECOM>update test set a= where =

session 会被锁住

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowExclusiveTEST

AAANoneTEST_CHILD

AAARowExclusiveTEST

AAARowExclusiveTEST_CHILD

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TMRowExclusive

TMNone

TMRowExclusive

TMRowExclusive

可见会发生死锁是由于第二个session 申请子表的share锁时发生的

对外键建立索引

create>aaa@AAAUSORACLECOM>create index idx_child on test_child(a)

索引已创建

当父子两个表同时更新时

session

update>aaa@AAAUSORACLECOM>update test_child set a= where =

已更新

Session

update>aaa@AAAUSORACLECOM>update test set a= where =

已更新

可见不会发生死锁

cellPadding= width=% bgColor=#cccccc>ff>

aaa@AAAUSORACLECOM>@showlockedobj

O_NAMESIDLOCK_TYPEOBJECT_NAMEXIDUSNXIDSLOT

XIDSQN

AAARowExclusiveTEST

AAARowshareTEST_CHILD

AAARowshareTEST

AAARowExclusiveTEST_CHILD

aaa@AAAUSORACLECOM>@showlocks

SIDTYPEIDIDLOCK_TYPEREQUESTCTIME

BLOCK

TMRowExclusive

TMRowshare

TMRowshare

TMRowExclusive

可以发现session 获得TEST_CHILD行级排他意向表锁同时获得TEST表的行级共享排他意向锁

session 获得TEST行级排他意向表锁同时获得TEST_CHILD表的行级共享排他意向锁

与上个例子相比区别在于前面的例子中session 获得TEST_CHILD和TEST行级排他意向表锁

也就是说对外键建立索引可以防止两个表的死锁

总结

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

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

上一篇:SQL与Oracle、DB2的性能比较

下一篇:oracle9i中Rman的备份使用点滴