应用场景
并发情况下为了保证资源不被相互争夺,每次请求都对数据加锁
原生实现
/**
* 扣减库存
* @return
*/
public String deductStock(){
//定义锁
String lockKey = "lockKey";
//设置锁ID 确保唯一
String cid = UUID.randomUUID().toString();
//添加一把实效30秒的锁 如果存在就不操作
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更方便的实现
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依赖
org.springframework.boot
spring-boot-starter-data-redis
org.redisson
redisson
3.5.0
@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);
}