本文主要描述在出现行级数据DML争用的过程中,达梦数据库是如何处理并发进行加锁的。
一、环境准备
1、首先构造一张事务表
create table t_test (id number, name varchar(20));
insert into t_test(id, name) values(1, DBMS_RANDOM.string('A', 20));
select * from t_test;
行号 ID NAME
---------- -- --------------------
1 1 XWsThNQujDlbdCXGOdtD
2、开启事务
开启一个会话1修改这一行记录,不提交:
update t_test set name='hello' where id=1;
影响行数 1
同时开启另一个新的会话2,修改同一行数据:
SQL> update t_test set name='hello' where id=1;
发现会话hang住
二、锁过程分析
下面我们看一下会话的锁情况。
首先通过select * from v$lock;查找到当前持有锁的事务号为7038,也就是会话1产生的。被锁的事务号是7039,也就是会话2产生的。
首先是7038:
SQL> select * from v$lock where trx_id=7038;
行号 ADDR TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_IDX TID IGN_FLAG HLCK_EP
---------- -------------------- -------------------- ------ ----- ----------- ----------- -------------------- -------------------- ----------- -----------
1 140316362438600 7038 OBJECT IS 0 302 0 7027 1 255
2 140316362439032 7038 OBJECT IS 0 268435456 0 7027 1 255
3 140316362439320 7038 OBJECT IX 0 1059 0 7038 0 255
4 140316362440040 7038 OBJECT IS 0 0 0 7027 1 255
5 140316362440616 7038 OBJECT IS 0 150994945 0 7028 1 255
6 140316362440904 7038 OBJECT IS 0 150994944 0 7028 1 255
7 140316362441336 7038 OBJECT IS 0 50331649 0 7027 1 255
8 140316362700744 7038 TID X 0 -1 -1 7038 0 255
8 rows got
解释一下7038事务保有的锁:
SQL> select object_id, object_name,OBJECT_TYPE from dba_objects where object_id in (302, 268435456, 1059, 0, 150994945, 150994944, 50331649);
行号 OBJECT_ID OBJECT_NAME OBJECT_TYPE
---------- --------- ----------- -----------
1 150994944 SYS SCH
2 150994945 SYSDBA SCH
3 0 SYSOBJECTS TABLE
4 1059 T_TEST TABLE
5 268435456 SYSOBJECTS DSYNOM
已用时间: 3.563(毫秒). 执行号:550.
其中SCH为模式类型,所以显然对模式类型增加了IS锁,意向共享锁
TABLE:表,对sysobjects增加了一个IS锁,对事务表增加了一个IX锁,意向排他锁
DSYNOM是对sysobjects的一个同义词,对TID 7038事务号持有排他锁X。
接下来看一下7039持有锁的情况:
SQL> select * from v$lock where trx_id=7039;
行号 ADDR TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_IDX TID IGN_FLAG HLCK_EP
---------- -------------------- -------------------- ------ ----- ----------- ----------- -------------------- -------------------- ----------- -----------
1 140316362439464 7039 OBJECT IX 0 1059 0 7039 0 255
2 140316362700888 7039 TID S 1 1059 1 7038 0 255
首先是一个object类型锁,1509,是对t_test表增加了一个IX锁,这印证了IX锁在表级是相容的,同时还有一个TID锁,是事务锁,这个事务锁是一个共享的,此时被X锁阻塞。
接下来,提交7038,查看7039持有的锁情况:
SQL> select * from v$lock where trx_id=7039;
行号 ADDR TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_IDX TID IGN_FLAG HLCK_EP
---------- -------------------- -------------------- ------ ----- ----------- ----------- -------------------- -------------------- ----------- -----------
1 140316362439464 7039 OBJECT IX 0 1059 0 7039 0 255
2 140316362700744 7039 TID X 0 -1 -1 7039 0 255
3 140316362700888 7039 TID S 0 1059 1 7038 0 255
已用时间: 1.073(毫秒). 执行号:552.
当7038提交以后,7039会将事务锁从共享转为排他,但这里的转换并不是简单的S和X之间的转换:
首先会话1,在创建事务时,生成7038事务号,并对7038持有X锁。当会话2修改同一行时,创建7039事务,会首先对这一行数据生成新的事务锁,这个锁其实是在7038事务号上面增加了一个S锁的等待,锁对象是7038的事务号。当7038提交之后,会话2便会持有7038事务号的S锁,同时对7039事务号持有X锁。从而完成了S与X的转换。
另外,在本实验中,我们注意到,在7039中,并没有对模式、数据字典持有锁,原因在于7039掌握有对7038的共享锁,而7038事务号中,已经对模式增加了对应的锁了(这在上面对7038的锁信息中有体现),所以显然7039是对模式具有共享锁的。所以在达梦数据库中,新的事务只需要对前一事务号保有共享锁即可,而无需再次对各对象增加锁,减少了行锁模式对系统资源的消耗。




