事务的定义:
DM 中事务是一个逻辑工作单元,由一系列 SQL 语句组成。DM 把一个事务的所有 SQL 语句作为一个整体,即事务中的操作,要么全部执行,要么一个也不执行。DM 没有提供显式定义事务开始的语句,第一个可执行的 SQL 语句(除登录语句外)隐含事务的开始。
用户可以使用显式的提交(COMMIT)或回滚语句(ROLLBACK)来结束一个事务(DML),也可以隐式地提交一个事务(DDL)。
事务的并发实现方式和封锁机制:
DM 数据库支持多用户并发访问(通过多版本并发控制MVCC实现),读写不会互相阻塞,但有可能出现多个事务同时访问、修改相同数据的情况。若对并发操作不加控制,就可能会访问到不正确的数据,破坏数据的一致性和正确性。DM 数据库采用封锁机制来解决并发问题。
锁的模式:
针对并发用户访问数据库资源,达梦数据库也提供了四种不同的锁模式:
共享锁:Share Lock,简称S锁,读操作,允许并发读取相同资源,不允许事务修改资源;
排它锁:Exclusive Lock,简称X锁,写操作,独占访问对象,不允许其他事务访问,一般在修改定义时使用;
意向共享锁:Intent Share Lock,简称IS锁, 一般在只读访问对象时使用;
意向排他锁:Intent Exclusive Lock,简称IX锁,一般在修改对象时使用;
各模式锁之间的相容矩阵
按照封锁对象不同,锁粒度可分为TID锁和对象锁:
TID锁:以事务号为封锁对象;每个活动事务生成一个TID锁,代替行锁功能(多版本写不阻塞读,select操作消除了行锁,DM没有行锁概念);DM属于行级多版本,每行隐含一个TID字段,用于事务可见性判断;insert、delete、update,设置事务号到TID字段,相当于对记录隐式上TID锁,不需要额外行锁,避免大量行锁消耗资源,只有多个事务同时修改同一行记录,才产生新的TID锁
对象锁:DM新引入的锁,通过统一的对象ID进行封锁,对数据字典的封锁和表的封锁,合并为对象锁,达到减少封锁冲突,提升系统并发性能;
1)数据字典锁:保护数据字段对象的并发访问,解决DDL并发和DDL/DML并发问题,防止多个事务同时修改同一个对象的字典定义,确保对同一个对象的DDL操作是串行,防止事务修改数据字典的同时被另一个事务修改对应表的数据
2)表锁:保护表数据的完整性,防止多个事务同时批量插入、更新一张表,防止向正在使用 FAST LOADER 工具装载数据的表中插入数据等,保证这些优化后数据操作的正确性。此外,表锁还有一个作用,避免对存在未提交修改的表执行 ALTER TABLE、TRUNCATE TABLE 操作。
为了方便用户查看当前系统中锁的状态,DM 数据库专门提供了一个 V$LOCK 动态视图。通过该视图,用户可以查看到系统当前所有锁的详细信息,如锁的内存地址、所属事务 ID、锁类型、锁模式等。
用户可以通过执行如下语句查看锁信息:
Copied SELECT * FROM V$LOCK;
其结果看起来和下面类似:
Copy行号 ADDR TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_IDX TID
---------- -------------------- -------------------- ----- ----- ----------
1 572815360 9173 TID X 0 -1 -1 9173
2 572815480 9172 TID X 0 -1 -1 9172
其中 ADDR 列表示锁的内存地址;TRX_ID 列表示锁所属的事务 ID;LTYPE 列表示锁的类型,可能是 OBJECT(对象锁)或者 TID(TID 锁);LMODE 表示锁的模式,可能的取值有 S(共享锁)、X(排他锁)、IS(意向共享锁)、IX(意向排他锁);BLOCKED 列表示锁是否处于上锁等待状态,0 表示已上锁成功,1 表示处于上锁等待状态;TABLE_ID 列对于对象锁,表示表对象或字典对象的 ID,对于 TID 锁,表示封锁记录对应的表 ID;ROW_IDX 列为 TID 锁封锁记录的行信息;TID 列为 TID 锁对象事务 ID。
阻塞与死锁:
阻塞和死锁是会与并发事务一起发生的两个事件,它们都与锁相关。
当一个事务正在占用某个资源的锁,此时另一个事务正在请求这个资源上与第一个锁相冲突的锁类型时,就会发生阻塞。被阻塞的事务将一直挂起,直到持有锁的事务放弃锁定的资源为止。死锁则是两个事务之间的互相阻塞,系统对于死锁有自动检测机制,然后会选择牺牲掉其中一个事务。
在 DM 数据库中,INSERT、UPDATE、DELETE 是最常见的会产生阻塞和死锁的语句。
INSERT 发生阻塞的唯一情况是,当多个事务同时试图向有主键或 UNIQUE 约束的表中插入相同的数据时,其中的一个事务将被阻塞,直到另外一个事务提交或回滚。一个事务提交时,另一个事务将收到唯一性冲突的错误;一个事务回滚时,被阻塞的事务可以继续执行。
当 UPDATE 和 DELETE 修改的记录,已经被另外的事务修改过,将会发生阻塞,直到另一个事务提交或回滚。
死锁处理的示例:
1.执行UPDATE TEST.DEPARTMENTS SET DEPARTMENT_NAME = 'OFFICE2' WHERE DEPARTMENT_ID = 2;
2.执行UPDATE TEST.DEPARTMENTS SET DEPARTMENT_NAME = 'OFFICE1' WHERE DEPARTMENT_ID = 1;
3.执行DELETE TEST.DEPARTMENTS WHERE DEPARTMENT_ID = 2;此时发现出现了阻塞,语句无法正常执行。
4.执行DELETE TEST.DEPARTMENTS WHERE DEPARTMENT_ID = 1;结果集中返回“死锁”
达梦在线服务平台:https://eco.dameng.com