简单的分布式锁 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
  • ‌避免嵌套‌:不在锁内调用其他带锁的方法
相关推荐
打工仔折腾 AI1 分钟前
鸿蒙移动端直连 Windows 远程桌面配置与性能调优实践
人工智能·windows·后端·python·华为·性能优化·harmonyos
罗四强4 分钟前
第10篇:打包上架:签名、打包 HAP、发布到华为应用市场
分布式·操作系统·harmonyos·arkts·鸿蒙系统
秋饼13 分钟前
Redis 全面解析:从数据结构到主从/哨兵/集群、分布式锁与面试高频考点,代码到原理一次讲透
数据库·redis·分布式·面试·后端开发
程序员飞哥14 分钟前
AI 编程额度怎么用才不浪费?
java·前端·后端
二月夜15 分钟前
Redis 高频面试题全解:缓存三大问题、大 key 治理与分布式锁之争(2026 招聘 JD 真题复盘)
redis·分布式·后端·缓存
IT_陈寒31 分钟前
Vite开发实战:从入门到精通
前端·人工智能·后端
樱花落木兰32 分钟前
Redis 消息队列的可靠性演进:从 List、Pub/Sub 到 Stream 消费者组,以及 8.x 版本改变了什么
java·开发语言·经验分享·redis·分布式·python·软件工程
学长毕设36 分钟前
基于SpringBoot的文具商城在线零售系统-附源码
spring boot·后端·零售
乐橙开放平台1 小时前
离岗检测怎么实现?通过客流相机或 AI 摄像头识别岗位区域无人状态,再推送告警消息
人工智能·笔记·后端·数码相机·物联网·自动化·音视频
真上帝的左手3 小时前
12. 消息队列-Kafka进阶
分布式·中间件·kafka