Spring Boot如何限制指定接口多用户并发且不影响同控制器其他接口
实现方案
你可以根据自身应用的部署模式选择对应方案,所有方案均不会限制第一个GET查询接口的并发能力,仅对第二个覆盖MongoDB集合的接口做并发互斥控制:
方案1:单体部署场景:本地锁
如果应用仅单实例部署,使用JVM本地锁即可实现需求,无需引入额外依赖:
- 在对应Controller中定义一个私有、不可变的专属锁对象,不要直接使用Controller实例本身作为锁,避免影响Controller内其他接口的执行
- 仅在第二个写接口的核心业务逻辑外层加锁
代码示例:
@RestController @RequestMapping("/demo") public class DemoController { // 专属锁对象,仅用于第二个接口的并发控制 private final Object overwriteLock = new Object(); // 第一个GET查询接口,无任何锁逻辑,并发不受限 @GetMapping("/query") public R queryData() { // 执行查询逻辑 return R.success(); } // 第二个覆盖集合的接口,加锁控制并发 @PostMapping("/overwrite") public R overwriteMongoCollection() { synchronized (overwriteLock) { // 执行MongoDB集合覆盖逻辑 return R.success(); } } }
注意:该方案仅适用于单实例部署,集群部署时不同实例的JVM锁不互通,会出现并发问题。
方案2:集群部署场景:Redis分布式锁(推荐)
如果应用是多实例集群部署,推荐使用Redisson实现分布式锁,无需自行处理锁续期、误释放等边界问题:
- 项目引入Redisson依赖,完成Redis连接配置
- 仅在第二个写接口中加分布式锁逻辑
代码示例:
@RestController @RequestMapping("/demo") public class DemoController { @Resource private RedissonClient redissonClient; // 第一个GET查询接口,无任何锁逻辑,并发不受限 @GetMapping("/query") public R queryData() { // 执行查询逻辑 return R.success(); } // 第二个覆盖集合的接口,加分布式锁控制并发 @PostMapping("/overwrite") public R overwriteMongoCollection() { RLock lock = redissonClient.getLock("mongo:collection:overwrite:lock"); try { // 尝试获取锁:最大等待3秒,锁默认持有30秒(可根据业务实际耗时调整) boolean lockAcquired = lock.tryLock(3, 30, TimeUnit.SECONDS); if (!lockAcquired) { return R.fail("当前有其他用户正在执行数据覆盖操作,请稍后重试"); } // 执行MongoDB集合覆盖逻辑 return R.success(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return R.fail("操作被中断"); } finally { // 确认当前线程持有锁才释放,避免误释放其他线程的锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
方案3:无额外中间件依赖:MongoDB原生分布式锁
如果不想额外引入Redis依赖,可直接利用MongoDB的特性实现分布式锁:
- 新建一个专门的锁集合
distributed_lock,给lock_key字段添加唯一索引,同时设置文档自动过期时间 - 执行集合覆盖操作前,尝试向
distributed_lock插入一条lock_key = "mongo_collection_overwrite"的记录 - 插入成功代表获取到锁,执行覆盖逻辑,执行完成后删除对应的锁记录
- 插入失败代表锁已被其他请求持有,直接返回重试提示即可
注意事项
- 锁逻辑仅包裹核心的集合覆盖业务代码,不要把参数校验、非核心查询等逻辑放到锁块内,尽量缩短锁持有时间
- 锁的超时时间需要根据集合覆盖的实际最大耗时合理设置,避免锁提前释放导致并发问题,或者锁持有时间过长影响可用性
- 锁释放操作必须放在
finally代码块中,避免业务抛出异常导致锁无法释放
内容的提问来源于stack exchange,提问作者Aakash Pathak
相关产品推荐
相关产品推荐

