Redisson 是一个用于 Java 的 Redis 客户端,它提供了丰富的功能,包括分布式锁。Redisson 的分布式锁实现了基于 Redis 的分布式锁,具有简单易用、可靠性高的特点。
以下是 Redisson 分布式锁的一些重要特性和用法:
可重入锁: Redisson 的分布式锁是可重入的,同一线程可以多次获取同一把锁,而不会出现死锁。
公平锁: Redisson 支持公平锁,即按照获取锁的顺序依次获取,避免了某些线程一直获取不到锁的情况。
锁超时: 可以为分布式锁设置过期时间,确保即使在某些情况下锁没有被显式释放,也能在一定时间后自动释放。
异步锁: Redisson 提供了异步的分布式锁,通过异步 API 可以在不阻塞线程的情况下获取和释放锁。
监控锁状态: Redisson 允许监控锁的状态,包括锁是否被某个线程持有,锁的过期时间等。
导入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.23.5</version>
</dependency>
application.yaml 配置:
spring:
redis:
host: 127.0.0.1
port: 6379
password:
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 1000ms
RedissonConfig配置:
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
/**
* RedissonClient,单机模式
*/
@Bean
public RedissonClient redisson() {
Config config = new Config();
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress("redis://" + host + ":" + port);
return Redisson.create(config);
}
}
利用Redisson分布式锁解决超卖问题,修改代码如下:
加锁 lock.lock()
阻塞等待,默认等待,加锁的默认时间都是30s,锁的自动续期,如果业务时间长,运行期间会自动给锁续上新的30s,不用担心业务时间长导致锁自动过期被删除,加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s后自动删除。
加锁 lock.lock(10,TimeUnit.SECONDS)
锁到期后,不会自动续期,如果传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间。如果未指定锁的超时时间,只要占锁成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10s就会自动进行续期。
@RestController
public class MyController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedissonClient redisson;
@RequestMapping("/buy/{id}")
public String buy(@PathVariable("id") Long id){
String message="error";
String lock_key="product_lock_"+id;
String key="product_" + id;
RLock lock = redisson.getLock(lock_key);
//try catch 设计是为了防止在执行业务的时候出现异常导致redis锁一直无法释放
try {
lock.lock();
int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(key));
if (count > 0) {
stringRedisTemplate.opsForValue().set(key, String.valueOf(--count));
System.out.println(key + "商品购买成功,剩余库存" + count);
message="success";
}
}catch (Throwable e){
e.printStackTrace();
}finally {
lock.unlock();
}
if(message.equals("error"))
System.out.println(key+"商品库存不足");
return message;
}
}