说在前面,Redis分布式锁的实现已经烂大街了。 很多人都写过博客,也有写的非常非常好的。 我这里纯属为了自己学习整理一下。 而且现在redis有一个超级牛逼的客户端 Redisson
原理主要是通过redis的nx自增来实现的。
下面就直接上代码
添加依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
分布式锁的业务无关性完全可以抽成一个接口
public interface DistributedLockTemplate {
/**
* 执行方法
* @param lockId 锁id(对应业务唯一ID)
* @param timeout 最大等待获取锁时间
* @param unit 等待时间单位
* @param callback 回调方法
* @return
*/
Object execute(String lockId, Integer timeout, TimeUnit unit, Callback callback);
}
下面就是实现类
private RedisLockRegistry redisLockRegistry;
引用的项目中的依赖 spring-integration-redis
流程如下: 先通过redisLockRegistry获取锁对象Lock, 在通过lock的tryLock方法尝试获取锁,并设置超时时间,如果获取到锁就调用callback中的成功业务逻辑 ,如果无法获取锁就调用callback中的失败获取锁逻辑。 下面会介绍Callback这个函数。 最后如果获取到了锁就释放锁。
@Slf4j
@Component
public class RedisLockTemplate implements DistributedLockTemplate {
@Autowired
private RedisLockRegistry redisLockRegistry;
@Override
public Object execute(String lockId, Integer timeout, TimeUnit unit, Callback callback) {
Lock lock = null;
boolean getLock = false;
try {
lock = redisLockRegistry.obtain(lockId);
getLock = lock.tryLock(timeout, unit);
if(getLock){
// 拿到锁
return callback.onGetLock();
}else{
// 未拿到锁
return callback.onTimeout();
}
}catch(InterruptedException ex){
log.error(ex.getMessage(), ex);
Thread.currentThread().interrupt();
}catch (Exception e) {
log.error(e.getMessage(), e);
}finally {
if(getLock) {
// 释放锁
lock.unlock();
}
}
return null;
}
}
下面是Callback接口
public interface Callback {
/**
* 成功获取锁后执行方法
* @return
* @throws InterruptedException
*/
Object onGetLock() throws InterruptedException;
/**
* 获取锁超时回调
* @return
* @throws InterruptedException
*/
Object onTimeout() throws InterruptedException;
}
分布式锁的使用
将我们定义的模板注入进来就可以使用了。
@Autowired
private RedisLockTemplate redisLockTemplate;
@RequestMapping(value = "/lockAndLimit", method = RequestMethod.GET)
@ResponseBody
public Result<Object> test1() {
redisLockTemplate.execute("订单流水号", 3, TimeUnit.SECONDS, new Callback() {
@Override
public Object onGetLock() throws InterruptedException {
// TODO 获得锁后要做的事
log.info("生成订单流水号");
return null;
}
@Override
public Object onTimeout() throws InterruptedException {
// TODO 未获取到锁(获取锁超时)后要做的事
log.info("oops 没拿到锁");
return null;
}
});
return ResultUtil.data(null);
}
简单分析
这里可以简单分析一下源码, 获取我们通过 lock = redisLockRegistry.obtain(lockId);
获取到的Lock对象是经过包装的。 是RedisLock.class的对象, 我们在调用trylock 和 unlock 都是调用的这个类中的方法。 当然了这个类也是实现 Lock接口的。
重要的事情
交个朋友吧
来源:oschina
链接:https://my.oschina.net/u/4256940/blog/4465134