一直以来对oracle的锁都没搞清楚,这次借考OCA的机会弄了一下。
实验如下(以下的结果是在oracle10g上测试的):
1.insert 语句
会话1--->
insert into p(x) values(8); //表p就一个字段,number类型
select * from v$lock where (type = 'TM' or type = 'TX') and sid = userenv('SID');
(假设系统只有该用户)查询结果为:
P表被锁住了,LMODE 3(TM锁:行排他锁),还有一个TX锁(LMODE=6)
会话2--->
如果这个时候另外一个用户登录,企图删除这个表:
drop table user1.p;
立刻抛出ora-00054的错误。
如果插入同样的数据,则被阻塞,直到上个用户提交或者回滚
2.update 语句
如果p表没有被c表作为外键关联,则和insert语句产生的锁是一样的。
下面我们来看一下有外键关系的情况:
假设现在有个c表关联了p表,p表的主键是c表的外键。假设现在c表有2条数据,对应p表的2条数据,p表6条数据。
会话1--->
update p set x=10 where x = 3;//假设该主键未被c表引用
此时如果表c的外键没有索引,则c表不会被锁柱,否则c表被锁住了(LMODE=2:行共享锁)。为什么
有了索引反而会锁住的呢?这个我也没搞明白。
还有一种情况,如果我先往c表插入一条数据:
insert into c(x) values(3);
会话2--->
delete from p where p.x = 6;
这时候这个会话被阻塞,因为它要对c表加个LMODE=4的共享锁,但会话1已经对它进行行共享锁了。
这个也是oracle产生死锁的主要原因(外键没有索引) 。如果我们在c表的外键加个索引,看看什么情况:
delete from p where p.x = 6;
0 rows deleted
很明显,这个时候不会试图锁住c表。
从上面的例子可以看出,删除主表的数据的时候(执行该DML语句的期间),如果子表外键没有索引,
则会锁住子表(LMODE=4:共享锁)。
----------------------------------------------------------------------------------------------------------------
Lock Lock Modes Permitted? | ||||
SQL Mode RS RX S SRX X | ||||
SELECT Y Y Y Y Y | ||||
INSERT RX Y Y N N N | ||||
UPDATE RX Y* Y* N N N | ||||
DELETE RX Y* Y* N N N | ||||
SELECT.. FOR UPDATE OF.. RS Y* Y* Y* Y* N | ||||
LOCK TABLE <table_name> | ||||
IN ROW SHARE MODE RS Y Y Y Y N | ||||
IN ROW EXCLUSIVE MODE RX Y Y N N N | ||||
IN SHARE MODE S Y N Y N N | ||||
IN SHARE ROW EXCLUSIVE MODE SRX Y N N N N | ||||
IN EXCLUSIVE MODE X N N N N N | ||||
RS: row share RX: row exclusive S: share | ||||
SRX: share row exclusive X: exclusive | ||||
* Waits if another transaction has a lock |
-------------------------------------------------------------------------------------------------------------
以上这段摘在oracle_locking文件,这里的S锁和SRX主要有什么区别呢?
1.一个事务锁住A表(S锁)之后,其他事务也能对该表进行S锁,当且仅当只有自己对该表有S锁时候才能
修改该表的数据。如果有多个事务都有该表的S锁,那谁都不能修改数据。只能等待其他事务结束。
2.一个事务锁住A表(SRX锁)之后,其他事务不能再对它进行SRX锁,只有自己才能更新数据。