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

Spring Boot如何限制指定接口多用户并发且不影响同控制器其他接口

实现方案

你可以根据自身应用的部署模式选择对应方案,所有方案均不会限制第一个GET查询接口的并发能力,仅对第二个覆盖MongoDB集合的接口做并发互斥控制:

方案1:单体部署场景:本地锁

如果应用仅单实例部署,使用JVM本地锁即可实现需求,无需引入额外依赖:

  1. 在对应Controller中定义一个私有、不可变的专属锁对象,不要直接使用Controller实例本身作为锁,避免影响Controller内其他接口的执行
  2. 仅在第二个写接口的核心业务逻辑外层加锁
    代码示例:
@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实现分布式锁,无需自行处理锁续期、误释放等边界问题:

  1. 项目引入Redisson依赖,完成Redis连接配置
  2. 仅在第二个写接口中加分布式锁逻辑
    代码示例:
@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的特性实现分布式锁:

  1. 新建一个专门的锁集合distributed_lock,给lock_key字段添加唯一索引,同时设置文档自动过期时间
  2. 执行集合覆盖操作前,尝试向distributed_lock插入一条lock_key = "mongo_collection_overwrite"的记录
  3. 插入成功代表获取到锁,执行覆盖逻辑,执行完成后删除对应的锁记录
  4. 插入失败代表锁已被其他请求持有,直接返回重试提示即可

注意事项

  • 锁逻辑仅包裹核心的集合覆盖业务代码,不要把参数校验、非核心查询等逻辑放到锁块内,尽量缩短锁持有时间
  • 锁的超时时间需要根据集合覆盖的实际最大耗时合理设置,避免锁提前释放导致并发问题,或者锁持有时间过长影响可用性
  • 锁释放操作必须放在finally代码块中,避免业务抛出异常导致锁无法释放

内容的提问来源于stack exchange,提问作者Aakash Pathak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:00:01