You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用连接Azure MS SQL发生死锁问题的解决求助

解决SQL Server死锁问题的方案

问题背景

  • 错误信息:com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 160) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
  • 使用JPA版本:2.7.12
  • 涉及操作:
    • 查询:带@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)的select * from employee where employee_id=10
    • 更新:update employee set emp_status='accept' where employee_id=10
  • 已尝试措施:更换JPA版本、排查索引问题
  • 需求:并发访问时不再出现死锁

解决方案

1. 替换乐观锁为悲观锁

OPTIMISTIC_FORCE_INCREMENT依赖版本字段实现乐观锁,并发场景下多个事务先查询再更新时,容易因锁时机冲突导致死锁。换成PESSIMISTIC_WRITE(写锁)或PESSIMISTIC_READ(读锁),在查询阶段直接获取行级锁,避免后续更新的锁竞争。
示例代码:

@Lock(LockModeType.PESSIMISTIC_WRITE)
Employee findByEmployeeId(Long employeeId);

注意要保证查询和更新操作在同一个事务内执行。

2. 合并查询与更新操作,减少锁持有步骤

不要拆分查询和更新两步走,直接用JPA的@Modifying注解执行更新语句,跳过查询环节,缩短锁的持有周期。
示例代码:

@Modifying
@Query("update Employee e set e.empStatus = 'accept' where e.employeeId = :id")
int updateEmployeeStatus(@Param("id") Long id);

3. 缩小事务边界

确保事务只包含核心的查询/更新操作,避免在事务中加入远程调用、文件IO等耗时操作,减少锁的持有时间,降低并发冲突概率。比如:

@Transactional(propagation = Propagation.REQUIRED)
public void updateStatus(Long id) {
    // 只放必要的更新操作,无额外冗余逻辑
    employeeRepository.updateEmployeeStatus(id);
}

4. 开启SQL Server快照隔离

SQL Server默认的READ COMMITTED隔离级别下,读操作会获取共享锁,容易和写锁冲突。开启READ COMMITTED SNAPSHOT后,读操作基于快照数据,不阻塞写操作,也不会被写操作阻塞,能大幅减少死锁。
执行SQL开启:

ALTER DATABASE YourDatabaseName SET READ_COMMITTED_SNAPSHOT ON;

5. 实现死锁重试机制

极端场景下死锁仍可能发生,因此需要在业务代码中添加重试逻辑。捕获SQLServerException,判断错误码为1205(死锁错误码)时,自动重试事务。
示例代码:

public void safeUpdateEmployeeStatus(Long id) {
    int maxRetries = 3;
    int retryCount = 0;
    while (retryCount < maxRetries) {
        try {
            updateStatus(id); // 调用带事务的更新方法
            return;
        } catch (SQLServerException e) {
            if (e.getErrorCode() == 1205) {
                retryCount++;
                try {
                    Thread.sleep(100 * retryCount); // 重试间隔递增
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            } else {
                throw e;
            }
        }
    }
    throw new RuntimeException("重试多次后仍无法完成更新,死锁问题未解决");
}

内容的提问来源于stack exchange,提问作者prajna parimita kheti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:10:30