使用redis实现分布式锁的主要原理是利用redis的原子性,有多个线程进行并发时只有一个线程可以设置成功
设置成功即获得了锁
如果出现异常,过了过期时间就直接释放
释放锁采用delete命令
释放锁之前要校验参数值,相同才能释放
@Slf4j
public class RedisLock implements AutoCloseable{
private RedisTemplate redisTemplate;
private String key;
private String value;
private int expireTime;
public RedisLock(RedisTemplate redisTemplate, String key, int expireTime) {
this.redisTemplate = redisTemplate;
this.key = key;
this.value = UUID.randomUUID().toString();
this.expireTime = expireTime;
}
public Boolean lock() {
log.info("我进入了方法");
RedisCallback<Boolean> redisCallback = connection -> {
// 设置NX
RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
// 超时时间
Expiration expiration = Expiration.seconds(expireTime);
byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);
Boolean result = connection.set(redisKey, redisValue, expiration, setOption);
return result;
};
Boolean lock = (Boolean)redisTemplate.execute(redisCallback);
return lock;
}
public Boolean unLock() {
String script = "if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n" +
" return redis.call(\"del\", KEYS[1])\n" +
"else\n" +
" return 0\n" +
"end";
List<String> keys = Arrays.asList(key);
RedisScript<Boolean> redisScript = RedisScript.of(script, Boolean.class);
// 释放锁的结果
Boolean result = (Boolean)redisTemplate.execute(redisScript, keys, value);
return result;
}
@Override
public void close() throws Exception {
unLock();
}
}
在业务代码中使用redis分布式锁
@Service
public class RedisLockService {
@Autowired
private RedisTemplate redisTemplate;
public String operation() {
try (RedisLock redisLock = new RedisLock(redisTemplate, "redisKey", 30)) {
// 如果成功获取锁
if (redisLock.lock()) {
// 执行业务代码
Thread.sleep(15000);
return "success";
}
} catch (Exception e) {
e.printStackTrace();
}
// 没获取到锁,返回失败
return "fail";
}
}
使用redission分布式锁
首先在pom文件中依赖redission
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.11.2</version>
</dependency>
使用redission自带的分布式锁
@Service
@Slf4j
public class RedisLockService {
@Autowired
private RedissonClient client;
public String redissionLock() {
RLock rLock = client.getLock("order");
rLock.lock(30, TimeUnit.SECONDS);
log.info("我获取到了锁!!!");
try {
Thread.sleep(10000);
return "success";
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
log.info("我释放了锁!!!");
rLock.unlock();
}
return "fail";
}
}