存储过程更新表时出现Transaction死锁错误该如何解决?
死锁问题解决方案
- 启用快照隔离或读提交快照隔离(RCSI)
这是最推荐的方案,无需修改现有查询代码,仅需在数据库层面开启配置,开启后SELECT查询会读取行版本数据,不会申请共享锁,从根本上避免和UPDATE操作的排它锁产生冲突。开启命令参考:-- 开启读提交快照隔离 ALTER DATABASE 你的数据库名 SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE; -- 如需更高隔离级别可开启快照隔离 ALTER DATABASE 你的数据库名 SET ALLOW_SNAPSHOT_ISOLATION ON; - 添加针对性索引缩小锁范围
确保两个UPDATE语句都能走高效索引,避免全表扫描导致锁定大量无关行,针对你当前的SQL,建议给table2添加联合索引:
该索引可以让table2的UPDATE操作直接定位到需要修改的行,大幅减少锁的持有范围和时间。CREATE NONCLUSTERED INDEX IX_table2_ResultBundleId_IsCancelled ON table2 (ResultBundleId, IsCancelled) INCLUDE (LastModified, WorkflowStage); - 统一所有事务的锁获取顺序
你当前的事务操作顺序是先更新table1再更新table2,需要确保所有操作这两张表的事务(包括其他更新、查询事务)都遵循相同的表访问顺序,消除死锁的循环等待必要条件。 - 添加死锁重试逻辑
死锁属于偶发异常,可在存储过程或者业务调用层添加错误捕获逻辑,当捕获到死锁错误号(1205)时,等待100-500毫秒后重新执行操作,建议设置最多3-5次重试阈值。 - 可选:查询添加NOLOCK提示(仅业务允许脏读时使用)
如果业务场景允许读取到未提交的临时数据,可以给并行运行的SELECT语句加上WITH (NOLOCK)提示,查询不会申请共享锁,也能避免和更新锁冲突,但要注意会有脏读、幻读等数据一致性问题。
内容的提问来源于stack exchange,提问作者masroore
相关产品推荐
相关产品推荐

