【DB2 数据库】11 模拟故障排查系列:锁等待与死锁(SQL0911N)实验
一、这篇文章要解决什么问题
前面几篇我已经把表空间、日志、实例启动这几条故障线跑通了。
这次我继续往并发问题走,专门验证两类很常见的现场:
- 锁等待(一个会话被另一个会话卡住)
- 死锁(两个会话互相等待,DB2 自动回滚其中一个)
这篇实验我想回答 4 个问题:
Lock-wait在 DB2 里到底怎么观察db2 list applications show detail里哪些字段最关键SQL0911N的Reason code "2"到底代表什么- 死锁发生后,数据是否能恢复到一致状态
二、实验环境
- 操作系统:
SUSE Linux Enterprise Server 12 SP5 - DB2 版本:
DB2 v9.7.0.6 Fix Pack 6 - 实例:
db2inst1 - 数据库:
TESTDB - 实验表:
TLOCK11 - 表空间:
USERSPACE1
三、实验前准备
我先建好实验表并插入两行基线数据,用来做交叉加锁。
# 删除旧表(若不存在会报 SQL0204N,属于正常)
db2 "drop table TLOCK11"
# 新建实验表
db2 "create table TLOCK11(id int not null primary key, c1 varchar(20)) in USERSPACE1"
# 初始化两行数据
db2 "insert into TLOCK11 values (1,'ROW-1')"
db2 "insert into TLOCK11 values (2,'ROW-2')"
# 验证初始化结果
db2 "select * from TLOCK11 order by id"我当时拿到的初始化结果是:
ID C1
----------- --------------------
1 ROW-1
2 ROW-2
2 record(s) selected.四、第一阶段:先做锁等待
这一阶段我开了三个终端:
- 终端 A:先更新
id=1并不提交,持有行锁 - 终端 B:再更新同一行
id=1,进入等待 - 终端 C:做监控观察
1. 终端 C 看到的应用状态
我在等待窗口里执行:
db2 list applications show detail关键行是:
DB2INST1 db2bp 47 *LOCAL.db2inst1.260511012524 ... Lock-wait ... TESTDB这说明确实存在会话在等锁。
2. 锁快照证据
我继续执行:
db2 get snapshot for locks on TESTDB快照里关键字段是:
Agents currently waiting on locks = 1并且可以看到一个会话持有 TLOCK11 的 Row X 锁,另一个会话处于 Lock-wait。
3. 释放后现象
我让持锁会话 rollback 后,等待会话返回成功。
这个结果符合锁等待的标准行为:不是报错,而是等到锁释放后继续执行。
五、第二阶段:构造死锁并触发 SQL0911N
第二阶段我用“交叉更新”的方式造死锁:
- 会话 A:先改
id=1 - 会话 B:先改
id=2 - 会话 A:再改
id=2(等待 B) - 会话 B:再改
id=1(形成环路)
1. 实际报错
在会话 B 的第二次更新,我拿到了目标报错:
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "2". SQLSTATE=40001这条报错就是这篇实验的核心证据。
Reason code "2" 对应死锁裁决,DB2 选中了一个事务作为 victim 并自动回滚。
2. 死锁后的监控快照
我在终端 C 复查:
db2 list applications show detail
db2 get snapshot for locks on TESTDB死锁后快照里有两个关键点:
Applications currently connected = 2
Agents currently waiting on locks = 0这说明 DB2 已经完成死锁裁决,等待环路被打破了。
另外我还能看到:
handle 59(db2bp)持有TLOCK11的两个Row X锁handle 74(db2bp)Locks held = 0
这和死锁自动回滚其中一个事务的行为是一致的。
六、实验收尾与一致性验证
死锁实验结束后,我让两个会话都执行了 rollback 并 terminate,最后再查表:
db2 connect to TESTDB
db2 "select * from TLOCK11 order by id"
db2 terminate最终结果是:
ID C1
----------- --------------------
1 ROW-1
2 ROW-2
2 record(s) selected.这说明两件事:
- 死锁中的 victim 事务已被 DB2 回滚
- 我手工收尾后,数据回到了实验前的基线状态
七、这次实验我记住的结论
第一,锁等待和死锁不是一回事。
锁等待通常是“等一会儿就过”,死锁是“谁都过不去,必须裁决一个回滚”。
第二,db2 list applications show detail 的 Status 很关键。
看到 Lock-wait 基本就能确认现场正在等锁。
第三,SQL0911N + Reason code 2 是死锁的典型信号。
排障时看到这一组,就要优先往事务访问顺序、并发更新路径去查。
第四,做并发实验时,收尾一定要显式 rollback + terminate。
否则下一个实验很容易被上一个会话的锁和事务状态污染。