目录
一、锁概述
锁是一种防止相互数据破坏的机制。当在访问共享数据的事务之间,错误的更新数据或更改数据结构,将引起数据一致性被破坏。锁在维护数据库并发性和一致性方面起着至关重要的作用。
二、锁模式
![](https://img-blog.csdnimg.cn/direct/0d3765523249417dbfd8a6ca2ee7c406.png)
三、达梦锁粒度
TID锁是达梦数据库中用于控制并发访问的一种锁机制。它以事务号作为锁的对象,为每个活动事务生成一把TID锁,用于防止多个事务同时修改同一行记录。与其他数据库的行锁不同,TID锁代替了行锁的功能。
举个例子来说明,假设有两个事务T1和T2同时想要修改同一行数据。在达梦数据库中,每个事务都有一个唯一的事务号(TID)。当T1开始执行修改操作时,它会把自己的事务号(TID1)设置到该行数据的TID字段中,相当于为该行数据隐式地加上了一把TID锁。此时,T1可以安全地修改这一行数据。而当T2也开始执行修改操作时,它发现该行数据的TID字段已经被T1占用了。此时,T2会生成一个新的TID锁,其锁对象为TID1(T1的事务号),而不是事务T2本身。这样,T2就知道该行数据正在被其他事务修改,并且需要等待T1完成修改后才能执行自己的修改操作。
TID锁的一个优点是它避免了大量行锁对系统资源的消耗。在执行INSERT、DELETE、UPDATE操作时,不再需要额外的行锁,而是通过设置事务号到TID字段来隐式地加上TID锁。只有多个事务同时修改同一行记录时,才会产生新的TID锁。
此外,达梦数据库还采用了多版本并发控制(MVCC)的方式。每一行记录都隐含一个TID字段,用于事务可见性判断。这意味着SELECT操作已经消除了行锁的概念,读操作不会被写操作阻塞。
四、锁管理机制与步骤
锁的管理这时候就需要引入锁管理中心的这个概念了,锁管理中心用于保锁的正确获取、释放和管理。下面举了一个例子,锁管理中心所进行的工作流程:
这个流程图描述了锁管理中心的工作过程,包括以下主要步骤:
- 事务/线程发起锁申请请求。
- 锁管理中心接收锁申请,并检查数据对象的锁状态。
- 根据锁类型兼容性判断,如果兼容,则分配共享锁;如果不兼容,则根据策略处理,可能导致等待或回滚等操作。
- 分配独占锁,并记录锁的时间戳。
- 事务持有锁进行操作。
- 定期检测锁超时,如果锁超时,则强制回收锁资源。
- 事务完成操作后,释放锁资源。
- 锁管理中心定期进行死锁检测,如果发现死锁,则根据策略进行处理,可能导致回滚事务等操作。
- 锁管理中心负责维护锁表和统计信息。
当然,达梦锁管理中心实现的比较复杂,实际的锁管理中心可能会涉及更复杂的算法和策略来处理锁分配、冲突检测、超时处理、死锁检测和维护锁表等任务。这里只是大致介绍锁管理中心的工作流程。
五、查看达梦锁,相关系统表
SELECT * FROM V$LOCK;
可以看到有很多列,
addr: 该列表示锁所存储的内存地址
irx_id: 锁所属的事务 ID
ltype:锁类型,对象锁,tid锁
lmode:锁的模式,is,ix,s,x四种模式
BLOCKED :锁是否处于上锁等待状态,0 表示已上锁成功,1 表示处于上锁等待状态
table_id:表示表对象或字典对象的 ID,对于 TID 锁,表示封锁记录对应的表 ID
六、锁相关操作演示
意向共享锁上锁:
查询t2表中的数据,并查看锁相关信息
select * from t2 ;
SELECT * FROM V$LOCK where table_id =1016;
如图所示,可以看到,对这张表添加了一个对象锁,并且锁的模式是意向共享锁
意向排他锁上锁:
往表中插入一条数据
insert into t2 values (1,1);
SELECT * FROM V$LOCK where table_id =1016;
已经有一个is意向共享锁,可以看到insert语句,加上的锁是ix 意向排他锁,并且和is锁并不冲突,而且也把trx_id该事务id加入到tid中
事务提交,释放锁资源:
这时,我们尝试继续对表进行插入和修改操作:
insert into t2 values (3,3);
SELECT * FROM V$LOCK where table_id =1016;
事务未提交,对表对象加的锁,并未解锁,所以在同一个事务当中,并不需要重复加锁
我们提交数据再进行插入:
commit;
insert into t2 values (2,2);
insert into t2 values (3,3);
SELECT * FROM V$LOCK where table_id =1016;
可以看见,该表在上一个事务提交后,锁资源释放,现在该事务155327重新加上ix锁
检查锁排斥规则:
这个时候对表进行加x锁,排他锁,查看锁状态
alter table "SYSDBA"."T2" add primary key("ID2");
可以看到,当表中有ix锁,再进行加排它锁,分配锁的时候,加锁超时,导致错误
TID锁机制:
开两个查询框,执行相同的修改操作,对同一行进行修改:
update t2 set id2 =10 where id2=1;
SELECT * FROM V$LOCK where table_id =1016;
事务155386对表进行修改操作
开一个新查询框,执行同样的操作:
update t2 set id2 =10 where id2=1;
SELECT * FROM V$LOCK where table_id =1016;
可以看到这个修改为执行,卡在加锁前了,未添加锁资源
如图可以看到,在执行update操作后,添加了一个ix锁,并未冲突,但对同一行进行修改,则会出发tid锁,可以看见对表1016又添加了一个TID锁的排他锁,但它的blocked列值为1,代表着为上锁成功,处于上锁等待状态,生成一个新的TID锁,其锁对象为155386(上一个事务事务1的事务号),这样,事务2就知道该行数据正在被其他事务修改,并且需要等待事务1完成修改后才能执行自己的修改操作。
提交事务1
查看事务2的锁情况:
可以看到事务155386已经提交后,相关锁资源释放,TID锁blocked列值为0,上锁成功