简单的分布式锁 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
  • 避免嵌套‌:不在锁内调用其他带锁的方法
相关推荐
你的人类朋友8 小时前
设计模式有哪几类?
前端·后端·设计模式
Yeats_Liao8 小时前
Go Web 编程快速入门 10 - 数据库集成与ORM:连接池、查询优化与事务管理
前端·数据库·后端·golang
想ai抽8 小时前
pulsar与kafka的架构原理异同点
分布式·架构·kafka
你的人类朋友9 小时前
适配器模式:适配就完事了bro!
前端·后端·设计模式
间彧9 小时前
SpringBoot集成RocketMQ事务消息
后端
间彧10 小时前
RocketMQ消息幂等控制:借助数据库唯一约束实现
后端
间彧10 小时前
RocketMQ消息幂等控制:借助Redis实现
后端
霸道流氓气质10 小时前
SpringBoot+MybatisPlus+自定义注解+切面实现水平数据隔离功能(附代码下载)
java·spring boot·后端