基于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
- 避免嵌套:不在锁内调用其他带锁的方法