简单的分布式锁 SpringBoot Redisson‌

基于SpringBoot和Redisson的分布式锁在实际开发中有多个经典应用场景,以下是几个典型的案例实现:

库存扣减防超卖

在电商秒杀场景中,使用Redisson的可重入锁保证库存扣减的原子性,有效防止超卖问题11。实现关键在于获取商品锁后执行库存检查与扣减:

java 复制代码
@Autowired 
private RedissonClient redissonClient;

public boolean reduceStock(Long productId, Integer quantity) {
    String lockKey = "product:stock:" + productId;
    RLock lock = redissonClient.getLock(lockKey);
    
    try {
        // 尝试获取锁,最多等待3秒,锁超时时间为10秒
        if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
            Integer stock = (Integer) redisTemplate.opsForValue()
                .get("product:stock:" + productId);
                
            if (stock >= quantity) {
                redisTemplate.opsForValue()
                    .set("product:stock:" + productId, stock - quantity);
                return true;
            }
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
    return false;
}
 

分布式任务调度控制

在集群环境下确保定时任务仅由一个节点执行,避免重复处理:

java 复制代码
public void executeScheduledTask() {
    RLock lock = redissonClient.getLock("scheduled:task:report");
    
    if (lock.tryLock()) {
        try {
            // 生成日报表逻辑
            generateDailyReport();
        } finally {
            lock.unlock();
        }
    }
}

接口幂等性保障

对于支付、订单创建等关键接口,通过分布式锁实现幂等控制8:

java 复制代码
public String createOrder(OrderRequest request) {
    String idempotentKey = "order:create:" + request.getOrderNo();
    RLock lock = redissonClient.getLock(idempotentKey);
    
    try {
        if (lock.tryLock(2, 30, TimeUnit.SECONDS)) {
            // 检查是否已处理
            if (orderService.existsByOrderNo(request.getOrderNo())) {
                return "订单已存在";
            }
            // 创建订单业务逻辑
            return orderService.createOrder(request);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return "处理失败";
}
 

热点数据缓存重建

防止缓存击穿,当缓存失效时仅允许一个线程查询数据库并重建缓存11:

java 复制代码
public User getUserById(Long userId) {
    String cacheKey = "user:info:" + userId;
    User user = (User) redisTemplate.opsForValue().get(cacheKey);
    
    if (user == null) {
        RLock lock = redissonClient.getLock("user:lock:" + userId);
        try {
            if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
                // 双重检查
                user = (User) redisTemplate.opsForValue().get(cacheKey);
                if (user == null) {
                    user = userMapper.selectById(userId);
                    redisTemplate.opsForValue().set(cacheKey, user, 30, TimeUnit.MINUTES);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    return user;
}

跨服务资源锁定

使用联锁(MultiLock)协调多个服务的资源操作11:

java 复制代码
public boolean updateMultiResources(Long orderId, Long productId) {
    RLock orderLock = redissonClient.getLock("order:lock:" + orderId);
    RLock inventoryLock = redissonClient.getLock("inventory:lock:" + productId);
    RLock multiLock = redissonClient.getMultiLock(orderLock, inventoryLock);
    
    try {
        if (multiLock.tryLock(5, 30, TimeUnit.SECONDS)) {
            // 同时锁定订单和库存资源
            orderService.update(orderId);
            inventoryService.update(productId);
            return true;
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        if (multiLock.isHeldByCurrentThread()) {
        multiLock.unlock();
        }
    }
    return false;
}

配置与依赖

在pom.xml中添加Redisson依赖:

XML 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId> 
    <version>3.23.5</version> 
</dependency> 

application.yml配置:

java 复制代码
spring:
  redis:
    host: 127.0.0.1
    port: 6379
  • 锁命名‌:使用业务相关的有意义的锁名称11
  • 超时设置‌:锁超时时间应大于业务执行最长时间11
  • 异常处理‌:确保锁最终被释放,避免死锁11
  • 看门狗机制‌:Redisson自动续期避免业务未完成锁过期11
  • 避免嵌套‌:不在锁内调用其他带锁的方法
相关推荐
阳光是sunny3 小时前
LangGraph中的Reducer是什么
前端·人工智能·后端
灯澜忆梦4 小时前
GO_并发编程---定时器
开发语言·后端·golang
阳光是sunny4 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
鱟鲥鳚4 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
皮皮林5514 小时前
开源实力派,给本地 AI 装上深度调研能力,一张 3090 跑到 95.7 分!
后端
努力的小雨5 小时前
把 Windows 桌面图标做成一个会自己运转的小世界
后端
武子康5 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
腾渊信息科技公司6 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
IT_陈寒7 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学7 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化