第一种方式:
加锁:
- Setnx命令加锁,并设置锁的有效时间和持有人标识
- Expir命令设置锁的过期时间、
解锁:
- 检查是否持有锁,然后删除锁;
- Delete命令删除锁
- 在使用redis实现分布式锁的时候,主要就会使用到这三个命令。
private StringRedisTemplate stringRedisTemplate;
private StringRedisTemplate stringRedisTemplate;
@Override
public int addRedPacket(RedPacketRecord redPacketRecord){
//redis加锁设置锁的失效时间
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(Constants.RED_PACKEXT_KEY +redPacketRecord.getUserId(),redPacketRecord.getRedId(),15,TimeUnit.MILLISECONDS);
if(flag) {
try {
//拿到分布式锁 --- 自己的锁自己解
List<RedPacketRecord> redPacketRecords = redPacketRecordMapper.selectByUserId(redPacketRecord.getUserId());
if(null == redPacketRecords || redPacketRecords.size() == 0){
return redPacketRecordMapper.insertSelective(redPacketRecord);
}
}finally {
//放在finally中防止异常无法解锁
//redis解锁,释放锁,删除锁,(删除之前做个判断,自己的锁自己解)
if(redPacketRecord.getRedId().equals(stringRedisTemplate.opsForValue().get(Constants.RED_PACKEXT_KEY +redPacketRecord.getUserId()))){
stringRedisTemplate.delete(Constants.RED_PACKEXT_KEY+redPacketRecord.getUserId());
}
}
}else {
//没有获取到分布式锁
return -1;
}
}
第二种方式:基于开源项目redisson.org
private RedissonClient redissonClient;
@Override
public int addRedPacket(RedPacketRecord redPacketRecord){
//获取到分布式锁
RLock rLock = redissonClient.getLock(Constants.RED_PACKEXT_KEY +redPacketRecord.getUserId());
//添加分布式锁,此时才会往redis里面放锁 500:表示如果500毫秒拿到锁就往下执行,30000表示过期时间
try {
if(rLock.tryLock(500,3000, TimeUnit.MILLISECONDS)){
try {
List<RedPacketRecord> redPacketRecords = redPacketRecordMapper.selectByUserId(redPacketRecord.getUserId());
if(null == redPacketRecords || redPacketRecords.size() ==0){
return redPacketRecordMapper.insertSelective(redPacketRecord);
}
} finally {
//释放锁
rLock.unlock();
}
} else {
//没有添加上分布式锁
return -1;
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if(rLock.isHeldByCurrentThread() && rLock.isLocked()){
rLock.unlock();
}
}
return 0;
}