一、事务锁定
1.
锁概述
锁是一种防止相互数据破坏的机制。当在访问共享数据的事务之间,错误的更新数据或
更改数据结构,将引起数据一致性被破坏。锁在维护数据库并发性和一致性方面起着至关重
要的作用。
DM
数据库支持多用户并发访问、修改数据,有可能出现多个事务同时访问、修
改相同数据的情况。若对并发操作不加控制,就可能会访问到不正确的数据,破坏数据的一
致性和正确性。
事务锁定:
事务锁定是数据库管理系统在处理并发事务时,为保证数据的一致性和完整性而采用的
一种技术。它通过对数据对象加锁,限制其他事务对锁定的数据对象进行修改操作,从而避
免了并发操作带来的问题。
2.
锁模式
1
)共享锁(
S
锁):也称为读锁,主要用于允许多个事务同时对同一份数据进行读取操作。
当一个事务对数据加上共享锁后,其他事务仍然可以对该数据加上共享锁,实现并发读取。
但是不允许其他事务对该数据进行写操作。
2
)排他锁(
X
锁):也称为写锁,主要用于确保数据在某一时刻仅被一个事务访问。当一
个事务对数据加上排他锁后,其他事务无法修改或查询该数据。
3
)意向锁: 意向锁是一种特殊的锁,主要用于解决并发事务之间的锁等待问题。当一个事
务准备对某一行数据进行读取或写入操作时,它首先需要获取该行的意向锁。多个事务可以
对相同对象上意向锁。
意向共享锁(
IS
锁):一般在只读访问对象时使用;
意向排他锁(
IX
锁):一般在修改对象数据时使用。

3.
锁粒度
按照封锁对象分
TID
锁和对象锁
1
)
TID
锁
即事务
ID
锁,以事务号作为锁的对象,为每个活动事务生成一把
TID
锁,用于在事务
执行过程中对数据加锁。
TID
锁可以确保在事务执行期间,防止多个事务同时修改同一行记
录,其他事务无法对锁定范围内的数据进行修改,以防止数据不一致和事务冲突。
假设有两个事务
T1
和
T2
同时想要修改同一行数据。在达梦数据库中,每个事务都有一
个唯一的事务号(
TID
)。当
T1
开始执行修改操作时,它会把自己的事务号(
TID1
)设置到
该行数据的
TID
字段中,相当于为该行数据隐式地加上了一把
TID
锁。此时,
T1
可以安全地
修改这一行数据。而当
T2
也开始执行修改操作时,它发现该行数据的
TID
字段已经被
T1
占
用了。此时,
T2
会生成一个新的
TID
锁,其锁对象为
TID1
(
T1
的事务号),而不是事务
T2
本身。这样,
T2
就知道该行数据正在被其他事务修改,并且需要等待
T1
完成修改后才能执
行自己的修改操作。
2
)对象锁
对象锁是
DM
新引入的一种锁,通过统一的对象
ID
进行封锁,将对数据字典的封锁和
表锁合并为对象锁,以达到减少封锁冲突、提升系统并发性能的目的。
4.
锁操作
创建表
T1
并查询该表表
ID
:

1
)查看锁

addr:
该列表示锁所存储的内存地址
irx_id:
锁所属的事务
ID
ltype
:锁类型,对象锁,
tid
锁
lmode
:锁的模式,
is
,
ix
,
s
,
x
四种模式
BLOCKED
:锁是否处于上锁等待状态,
0
表示已上锁成功,
1
表示处于上锁等待状态
table_id
:表示表对象或字典对象的
ID
,对于
TID
锁,表示封锁记录对应的表
ID
ROW_IDX
:改列为
TID
锁封锁记录的行信息
tid
:
TID
锁对象事务
ID
2
)意向共享锁上锁

3
)意向排他锁

再插入数据,加上的锁是
IX
锁并且和已有的
IS
锁不冲突
4
)事务提交后再插入数据,锁资源释放,现在重新对该表加锁,
TID
不同

5
)验证锁冲突
使用一个事务给表上排他锁后,用另一个事务不能再对这个事务上
S
锁
同时该事务也不能再对表中数据修改


二、多版本并发控制
MVCC
1.
概念
通过保存数据在某个时间点的快照来实现并发控制的。也就是说,不管事务执行多长时
间,事务内部看到的数据是不受其它事务影响的,根据事务开始的时间不同,每个事务对同
一张表,同一时刻看到的数据可能是不一样的。
2.
参数
TRX_VIEW_MODE
使用参数
TRX_VIEW_MODE
控制
MVCC
事务可见性的模式
TRX_VIEW_MODE=0
:事务启动前收集当前时刻的活动事务
ID
构造可见性视图,以确定某一
特定事务是否对当前事务可见;
TRX_VIEW_MODE=1
:系统维护事务提交历史,以此判断事务可见性。
DM
数据库基于物理记录和回滚记录实现行级多版本支持,数据页中只保留物理记录的
最新版本,通过回滚记录维护历史版本,所有事务针对特定的版本进行操作。
3.
可见性规则
实现多版本控制的关键是可见性判断,找到对当前事务可见的特定版本数据。
DM
通过
活动事务表,确定事务的可见性。根据事务隔离级的不同,在事务启动时(串行化),或者
语句执行时(读提交),收集这一时刻所有活动事务,并记录系统中即将产生的事务号
NEXT_TID
。
每一条物理记录中包含了两个字段:
TID
和
RPTR
。
TID
保存修改记录的事务号,
RPTR
保
存回滚段中上一个版本回滚记录的物理地址。插入、删除和更新物理记录时,
RPTR
指向操
作生成的回滚记录的物理地址。
TRXID
:事务的唯一标识符。每个事务在数据库中都有一个唯一的
TRXID
,它用于跟踪
和识别数据库中的各个事务。
1
)物理记录的
TRXID
等于当前事务号,说明是本事务修改的物理记录,物理记录可见
;
2
)物理记录的
TRXID
不在活动事务表中,并且
TRXID
小于
NEXT_TID
,物理记录可见
;
3
)物理记录的
TRXID
包含在活动事务表中,或者
TRXID
大于等于
NEXT_TID
,物理记
录不可见
;
事务一创建表并查询
PRXID
:

事务二查询
TRXID
显示一样:

事务一执行更新语句但不提交并查询
TRXID
:


事务二查询最大事务号:

因为会话一物理记录的
TRXID:8117
小于等于当前最大事务号:
8129
, 所以在能在本事
务里看见,其他事务里看不见。
会话二物理记录的
TRXID:8071
不在当前事务中,并且小于
NEXT_TID
,所以其物理记录
可见。
三、锁等待与死锁
1.
概念
阻塞:
当一个事务正在占用某个资源的锁,此时另一个事务正在请求这个资源上与第一个锁相
冲突的锁类型时,就会发生阻塞。被阻塞的事务将一直挂起,直到持有锁的事务放弃锁定的
资源为止。
死锁:
两个事务都在等待对方持有的资源锁,要等待对方释放有的资源锁之后才能继续工作,
两者互不想让,坚持到底,都在等待彼此完成才继续工作,就是这样的状态,双方都完成不
了,从而陷入死循环。
2.
处理
死锁不用人工干涉,数据库系统自动识别并解除。但是死锁是非正常情况,需要找到死
锁原因后,从应用逻辑层解决。
阻塞可能是应用流程涉及提交慢导致,但是最终也会提交或者回滚,所以一般情况下也
会自动消除。如果阻塞很长时间没有消除,在数据库层可以通过
SP_CLOSE_SESSION(SESSID);
来强制终阻塞源头的会话使其回滚,来解除阻塞,但是这个需要用户确认,不能私自操作。
锁等待解决方法
但实际业务中,我们可能无法手工提交阻塞的会话,此时可以强制杀死会话:
使用如下语句查询处于等待的锁(或查询
v$trxwait
可以查看阻塞事务):
select TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, TID
from v$lock where blocked=1;
根据会话
ID
,使用
sp_close_session
系统过程即可杀死会话
3.
检测
创建测试表并插入数据

插入数据但不提交,此时可以看到该表新增了
X
锁并且该锁
BLOCKED=1
,该锁被
8148
事务
阻塞


此时新开一个事务在进行插入数据,由于主键存在所以会被阻塞

四、学习心得
通过学习达梦数据库的事务锁定与并发控制,我深入了解事务锁定与并发控制原理,掌
握不同类型的锁及其使用场景。在以后的实际生产场景中我会根据实际业务需求,调整事务
锁定与并发控制的策略,以提高系统性能。时刻注意观察锁冲突现象,掌握解决锁冲突的方
法。深入理解并发控制原理,学会在实际项目中应用并发控制策略,提高系统的并发处理能
力。学习达梦数据库事务锁定与并发控制,对于我提高数据库管理水平具有重要意义。