简单的分布式锁 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
  • 避免嵌套‌:不在锁内调用其他带锁的方法
相关推荐
计算机毕设vx_bysj68691 小时前
计算机毕业设计必看必学~Springboot教学进度管理系统,原创定制程序、单片机、java、PHP、Python、小程序、文案全套、毕设成品等!
java·spring boot·vue·课程设计·管理系统
q***11653 小时前
Spring 中的 @ExceptionHandler 注解详解与应用
java·后端·spring
用户21411832636024 小时前
Gemini 3 Pro 来了!一句话生成完整网站,AI编程能力断层领先
后端
码事漫谈4 小时前
Linux开发到底指什么?是什么岗位?做什么的?
后端
码事漫谈4 小时前
Windows开发:一场与指针的共舞,亦是超越它的征程
后端
f***45325 小时前
基于SpringBoot和PostGIS的各省与地级市空间距离分析
android·前端·后端
Felix_XXXXL5 小时前
mysql查看binlog日志
java·后端
leonardee5 小时前
Plugin ‘mysql_native_password‘ is not loaded`
java·后端
百锦再6 小时前
第17章 模式与匹配
开发语言·后端·python·rust·django·内存·抽象
q***18846 小时前
Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决
java·spring boot·logback