spring boot 全局异常处理可以通过配置 @controlleradvice 结合自定义的 handlerexceptionresolver 或 @exceptionhandler 来捕获分布式锁竞争异常。具体做法是定义一个专门处理锁冲突异常的处理器,在方法上标注 @exceptionhandler 并指定对应的异常类(如 lockconflictexception),这样当业务代码抛出该异常时,spring mvc 会自动将其路由到该方法进行处理,返回统一的错误响应。

如何定义全局异常处理器以拦截锁冲突
通过继承 HandlerExceptionResolver 接口或直接在 @ControllerAdvice 中使用 @ExceptionHandler 可以拦截特定异常。推荐使用 @ExceptionHandler 方式,因为它更简洁且与 Spring MVC 集成更好。需要确保异常类被正确抛出,并且在全局处理器中匹配到它。

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(LockConflictException.class)
public ModelAndView handleLockConflict(HttpServletRequest request, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error/lock_conflict");
modelAndView.addObject("message", "资源正被其他用户占用,请稍后重试");
return modelAndView;
}
}
如何在业务代码中抛出锁竞争异常
在使用 Redisson 等分布式锁实现时,若尝试获取锁失败,应主动抛出 LockConflictException。这通常发生在 tryLock 方法返回 false 时。开发者需在调用锁逻辑的代码块中检查返回值,并在失败时抛出预定义的异常,以便全局处理器捕获。

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final RedissonClient redissonClient;
public OrderService(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
public void processOrder(String orderId) {
RLock lock = redissonClient.getLock("order_lock:" + orderId);
try {
if (!lock.tryLock(10, 30, java.util.concurrent.TimeUnit.SECONDS)) {
throw new LockConflictException("订单正在处理中");
}
// 执行业务逻辑
doProcess(orderId);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取锁中断", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
private void doProcess(String orderId) {
System.out.println("Processing order: " + orderId);
}
}
当多个请求同时竞争同一订单锁时会发生什么
当多个请求同时竞争同一订单锁时,只有第一个成功获取锁的请求会执行业务逻辑,其余请求会因 tryLock 返回 false 而抛出 LockConflictException,进而被全局异常处理器捕获并返回友好提示。这种机制确保了数据一致性,同时避免了线程阻塞等待。











