sql事务死锁是多个事务相互等待对方锁导致的循环依赖,数据库自动检测并终止牺牲者事务;需通过系统健康会话提取xml死锁报告,分析victim-list、waitresource和inputbuf定位根因,结合访问顺序统一、索引优化、缩短事务等策略预防。

SQL事务死锁不是数据库“卡住”,而是两个或多个事务相互等待对方持有的锁,形成循环依赖,导致谁都无法继续执行。数据库会自动检测并终止其中一个事务(牺牲者),抛出死锁异常。排查关键在于快速定位谁在等什么、谁被选为牺牲者、以及为什么会产生循环等待。
查看死锁日志与图形化报告
SQL Server默认记录死锁事件到系统健康会话(system_health)中,可通过以下方式提取:
- 查询XML死锁报告:SELECT CAST(event_data AS XML) AS DeadlockGraph FROM sys.fn_xe_file_target_read_file('system_health*.xel', NULL, NULL, NULL) WHERE object_name = 'xml_deadlock_report'
- 在SSMS中右键该XML → “查看死锁图”,可直观看到参与事务、线程、资源(如表/索引键)、等待关系及被选为牺牲者的进程
- 重点关注victim-list和process-list中的inputbuf(实际SQL语句)、waitresource(如KEY: 5:72057594044870656 (8194a02e9e3c)(表示某索引的某一行)
分析常见死锁模式
多数死锁源于访问顺序不一致或锁粒度不合理:
- 访问顺序不一致:事务A先更新表X再更新表Y,事务B却先更新Y再更新X → 极易形成环。解决方案是统一业务层操作顺序(如始终按“用户→订单→订单明细”顺序更新)
- 非必要范围锁:未使用索引字段WHERE条件,导致扫描全表或大范围页锁;或UPDATE/DELETE缺少有效SARG条件,引发锁升级。建议添加覆盖索引、避免函数/类型转换干扰索引使用
- 长时间持有写锁:事务内混杂I/O、远程调用、复杂计算,延长锁持有时间。应拆分事务,把非DB操作移出事务边界
预防与优化策略
死锁无法100%杜绝,但可大幅降低发生概率:
- 尽量缩短事务持续时间:只在真正需要原子性时开启事务,DML后尽快提交
- 按固定顺序访问对象:同一业务逻辑中,对多张表/行的修改严格遵循约定顺序
- 合理使用隔离级别:读操作优先用READ COMMITTED(默认)或更低;避免长期持有共享锁可考虑READ COMMITTED SNAPSHOT(启用行版本控制)
- 捕获并重试死锁异常:应用层捕获错误号1205(SQL Server)或类似码,自动重试被终止的事务(注意幂等性)
辅助诊断工具与命令
运行时快速定位活跃阻塞链:
- SELECT * FROM sys.dm_exec_requests WHERE blocking_session_id 0 — 查看当前被阻塞会话
- DBCC TRACEON (1222, -1) — 开启全局死锁跟踪(输出到错误日志,含详细资源信息)
- sp_who2 或 sys.dm_exec_sessions + sys.dm_tran_locks 关联查询,识别长期未提交事务及对应锁










