#####应用场景
并发情况下为了保证资源不被相互争夺,每次请求都对数据加锁
#####原生实现
public String fangzh(){
//定义锁
String lockKey = "lockKey";
//设置唯一锁ID 为了不乱解锁 只能解自己的锁
String cid = UUID.randomUUID().toString();
//加锁操作利用redis的setNX原子操作 设置10秒失效防止方式出错锁死,
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey,cid,10, TimeUnit.SECONDS);
if(!result){ //如果存在就
return "锁被占用!";
}
try {
//模拟业务操作 获取库存数量
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if(stock>0){
System.out.println("当前库存:"+stock);
stock = stock-1;
//扣减库存
redisTemplate.opsForValue().set("stock",stock);
}else{
System.out.println("库存不足:"+stock);
return "error";
}
}catch (Exception e){
e.printStackTrace();
}finally {
//不管怎么样最后都要解锁 并且要判断 是不是自己加的锁
if(cid.equals(redisTemplate.opsForValue().get(lockKey))){
redisTemplate.delete(lockKey);
}
}
return "success";
}
以上方法基本情况下使用没问题,
但是在特殊情况下, 锁的过期时间永远无法预估。
如果业务实现操作时间过长,或者集群情况下切换服务的时候 会导致服务无法使用 必须等到锁失效。
#####使用Redisson更方便的实现 使用 Redisson
public String deductStock2(){
String lockKey = "lockKey";
//获取redis锁
RLock redissonLock = redisson.getLock(lockKey);
try {
//加锁
redissonLock.lock();
//模拟业务操作
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if(stock>0){
System.out.println("当前库存:"+stock);
stock = stock-1;
redisTemplate.opsForValue().set("stock",stock);
}else{
System.out.println("库存不足:"+stock);
return "error";
}
}catch (Exception e){
e.printStackTrace();
}finally {
//释放锁
redissonLock.unlock();
}
return "success";
}
jar依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.0</version>
</dependency>
@Bean
public RedissonClient redisson(){
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379")
.setDatabase(9)
.setPassword("123456");
return Redisson.create(config);
}