分布式锁超时本身不触发事务回滚,仅使锁失效;真正回滚由业务异常和@Transactional配置决定,如乐观锁失败、唯一键冲突或手动抛出BusinessException等,经rollbackFor指定后由Spring自动回滚。

分布式锁超时本身不直接触发事务回滚,它只是让锁失效;真正决定是否回滚的,是业务逻辑中对异常的捕获与事务边界的控制。关键在于:锁超时 ≠ 业务失败,但锁提前释放可能引发并发冲突,进而导致数据异常——这时才需要回滚。
锁超时如何间接导致需回滚的异常
当锁在业务执行中途过期,其他线程可能抢入并修改同一资源(如重复扣库存、重复退款),后续校验或数据库唯一约束会抛出明确异常,比如:
-
乐观锁失败:版本号不匹配,
OptimisticLockException -
唯一键冲突:插入重复订单号,抛出
SQLIntegrityConstraintViolationException - 业务校验失败:查到库存已为0,手动 throw new BusinessException("库存不足")
在 Spring 中结合 @Transactional 实现自动回滚
确保方法被 @Transactional 修饰,并配置可回滚异常类型:
@Transactional(rollbackFor = {Exception.class, BusinessException.class})
public void processOrder(String orderId) {
// 1. 尝试获取分布式锁(带超时)
boolean locked = redisLock.tryLock("order:" + orderId, 30, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("操作繁忙,请稍后重试");
}
try {
// 2. 执行核心业务:查库存 → 扣减 → 创建订单
Order order = orderService.getOrderByOrderId(orderId);
if (order == null) {
throw new BusinessException("订单不存在");
}
inventoryService.deduct(order.getItemId(), 1); // 可能因并发触发异常
orderService.createOrder(order);
} finally {
// 3. 必须释放锁(注意:只释放自己持有的)
redisLock.unlock();
}
}
只要上述任意一步抛出被 rollbackFor 涵盖的异常,Spring 会自动回滚当前事务内的所有数据库操作。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
立即学习“Java免费学习笔记(深入)”;
主动检测锁有效性,提前中断并回滚
适用于长流程(如调用第三方支付接口耗时不可控)。可在关键步骤前检查锁是否仍有效:
- 使用 Redisson 的
RLock.isLocked()或自定义锁支持isValid()方法 - 若锁已丢失,立即 throw 异常,交由事务管理器回滚
- 示例逻辑:
if (!lock.isValid()) { log.warn("Lock lost unexpectedly for key: {}", lockKey); throw new IllegalStateException("Distributed lock expired during processing"); }
避免“锁过期但事务未回滚”的典型错误
常见陷阱包括:
- 事务范围包裹了锁获取,但没包裹锁释放:导致 unlock() 抛异常时事务已提交
-
忽略非运行时异常:如
IOException默认不触发回滚,需显式写rollbackFor = IOException.class - 锁续期失败未处理:看门狗线程异常退出,锁静默过期,业务却继续执行

















