简单的分布式锁 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
  • 避免嵌套‌:不在锁内调用其他带锁的方法
相关推荐
盒马盒马5 分钟前
Rust:内部可变性 & 型变
开发语言·后端·rust
苦学编程的谢12 分钟前
RabbitMQ_7_高级特性(4)
分布式·rabbitmq
无限大619 分钟前
为什么玩游戏需要独立显卡?——GPU与CPU的分工协作
后端·程序员
赵榕25 分钟前
RabbitMQ发布订阅模式同一消费者多个实例如何防止重复消费?
分布式·微服务·rabbitmq
Moment31 分钟前
小米不仅造车,还造模型?309B参数全开源,深度思考完胜DeepSeek 🐒🐒🐒
前端·人工智能·后端
马卡巴卡41 分钟前
SpringBoot集成Spring Statemachine(状态机)实战教程
后端
酒酿萝卜皮1 小时前
Elastic Search 安装使用
后端
古城小栈1 小时前
雾计算架构:边缘-云端协同的分布式 AI 推理
人工智能·分布式·架构
kkk_皮蛋1 小时前
信令是什么?为什么 WebRTC 需要信令?
后端·asp.net·webrtc
lang201509281 小时前
Kafka高可用:延迟请求处理揭秘
分布式·kafka·linq