创建测试表
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维护行级锁的开销使其在数据库并发控制方面有着明显的优势