1.场景还原
在并发的场景,分布式锁是一种比较常规且实用的解决方案;今天笔者就springboot中如何实现redis分布式锁作个讲解
2.关注点
实现redis分布式锁的关键在于设置储存值与过期时间要保证是一个原子性操作,否则会发生死锁
3.实现方案
1、pom依赖
<!--集成redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、redis锁实现
/**
* @auther xxx
* @date 2018/7/21 10:23
*
* redis 分布式锁 加锁与解密配套使用
*/
@Component
@Slf4j
public class RedisLock {
@Autowired
private HashRedisTemplate stringRedisTemplate;
/**
* 加锁
* @param key 锁唯一标志
* @param timeout 超时时间
* @return
*/
public boolean lock(String key, long timeout){
String value = String.valueOf(timeout + System.currentTimeMillis());
if(stringRedisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
//判断锁超时,防止死锁
String currentValue = (String)stringRedisTemplate.opsForValue().get(key);
//如果锁过期
if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){
//获取上一个锁的时间value
String oldValue = (String) stringRedisTemplate.opsForValue().getAndSet(key,value);
if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue) ){
//校验是不是上个对应的商品时间戳,也是防止并发
return true;
}
}
return false;
}
/**
* 解锁
* @param key
* @param value
*/
public void unlock(String key,String value){
try {
String currentValue = (String) stringRedisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value) ){
stringRedisTemplate.opsForValue().getOperations().delete(key);//删除key
}
} catch (Exception e) {
log.error("[Redis分布式锁] 解锁出现异常了,{}",e);
}
}
}