Redis分布式锁

那年仲夏 提交于 2020-08-06 07:59:11

说在前面,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接口的。
在这里插入图片描述

一篇比较不错的介绍分布式锁的文章

重要的事情

交个朋友吧
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!