关于锁和隔离级别的基础概念在这里就不提了,只讨论DB2与其他主流数据库关于锁的区别
DB2的隔离级别有4种(默认 CS):
UR:未提交读离级别,即读的时候不加锁,可以读到未提交的数据
CS:游标稳定性隔离级别,即读到哪一行就在这一行加S锁,读完就释放,类似游标一样。
RS:读稳定性隔离级别,即把查询的结果集都加S锁。
RR:可重复读隔离级别,即把读过的行都加S锁。
锁模式
表锁模式
强类型表锁
默认不会加强类型表锁,只有lock table或锁升级才会加该类型锁
弱类型表锁
即意向锁,配合行锁,获得行锁前必须获得表锁
查看锁:
db2pd -d ys -locks
执行sql取消自动提交使用+c
db2 +c "lock table test_1 in exclusive mode"
行锁模式
在获得行锁之前,需要先获取最低要求的表锁,例如要查询表中某行,需要获取表的意向读锁(IS),如果要增删改某行,需要获取表的意向写锁(IX)
锁的常见问题
锁等
当一个事务尝试获取某个资源(如表、行、索引等)的锁时,如果该资源已被其他事务锁定且不兼容,当前事务会进入等待状态
锁超时
如果等待时间超过 LOCKTIMEOUT
参数设定的阈值,则触发锁超时错误(SQL0911)
死锁
两个或多个事务相互等待对方释放锁,导致无限期阻塞。DB2 会自动检测死锁,并回滚其中一个事务(受害者事务),返回错误码 SQL0911
锁升级
当单个事务持有的行锁数量超过阈值时,DB2 会将多个行锁升级为单个表锁,以减少锁内存占用。锁升级可能引发并发性能下降
控制锁升级的参数
LOCKLIST:分配给锁的内存上限
MAXLOCKS:单个事务可占用锁内存的百分比阈值
锁转换
事务因操作需要将现有锁升级为更严格的锁模式。比如从 共享锁
转换为 排他锁
,锁转换可能导致其他事务的等待或死锁。
锁升级和锁转换本质完全不同,锁升级是行锁变表锁,锁转换是从弱类型锁转化为强类型锁的过程
锁监控与分析
通过snapshot monitor
、 event monitor
工具来检测锁
通过db2diag.log
来分析锁升级
锁等比较麻烦:
可以编写脚本监控,也可以使用db2pd
db2pd -d ys -locks showlocks wait -tra -app -dyn > lock_1.out
锁超时需要通过db2pd
结合db2cos
回调脚本来分析
死锁需要通过deadlock event monitor
监控
DB2还在9.7版本开始引入CREATE EVENT MONITOR FOR LOCKING
当前已落实
DB2 9.7引入的当前已落实(Currently Committed,CC)机制从根本上解决了该问题。CC是CS隔离级别的一种新实现,目的是防止写操作阻碍读操作(writeblocksread),减少锁等而提高并发性。在CC机制下,一个事务做update和delete 操作,但未提交,另一个事务读取该行时会从日志中获取已落实版本的数据,即update和delete之前的数据,而无须等待;一个事务做 insert 操作,但未提交,另一个事务读取时会忽略新插入数据,无须等待。