springboot2使用RedisTemplate开发分布式锁的正确打开

由于工作项目采用微服务架构, 每个应用分布式部署, 所以需要开发一个分布式锁, 由于所有的业务系统共用一个库, 所以之前已经写好一个基于数据库的分布式锁实现,但是效率上有欠缺, 所以需要开发一个基于redis的分布式锁,对于基于数据库的分布式锁和基于redis的分布式锁和基于zookeeper的分布式锁的优缺点,可自行在网上查阅, 这里只想讲一下redis与springboot封装的redistemplate集成的具体实现。

1. 引入相关依赖 , Maven 方式


    org.springframework.session
    spring-session-data-redis
    true --这个可选, 由于我这个jar包属于被其他系统引用的底层jar包, 是否使用redis可由具体的业务系统决定



    redis.clients
    jedis
    2.9.0
    true



    com.alibaba
    fastjson
    1.2.47
    true

2. 加锁代码段

/**
     * redis 加锁
     * LOCK_SUCCESS = "OK";
     * SET_IF_NOT_EXIST = "NX";
     * SET_WITH_EXPIRE_TIME = "PX";
     *
     * String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); 其实如果使用jedis原生代码的话, 是执行这段语句
     *
     * @param lockName
     * @param uniqueId
     */
    public void lock(String lockName, String uniqueId) {
        String lockKey = LOCK_PREFIX+lockName;
        String successMsg = StrUtil.format("{}-{}加锁成功!",lockName,uniqueId);
        String failMsg = StrUtil.format("{}-{}加锁失败[Redis]!",lockName,uniqueId);
        int expireTime = PropertyUtil.getInt("lock.expire.time");
        Boolean result = redisTemplate.execute(new RedisCallback() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.set(lockKey.getBytes(),uniqueId.getBytes(), Expiration.from(expireTime, TimeUnit.SECONDS), RedisStringCommands.SetOption.SET_IF_ABSENT);
            }
        });
        printResult(result, successMsg, failMsg);
    }

3. 解锁代码段

/**
     * redis 解锁:eval函数在redis集群环境中不支持, 具体查看spring源码
     * @See JedisClusterScriptingCommands
     *
     * Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
     * @param lockName
     * @param uniqueId
     */
    public void unlock(String lockName, String uniqueId) {
        String lockKey = LOCK_PREFIX+lockName;
        String successMsg = StrUtil.format("{}-{}解锁成功[Redis]!",lockName,uniqueId);
        String failMsg = StrUtil.format("{}-{}解锁失败[Redis]!",lockName,uniqueId);
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript redisScript = new DefaultRedisScript(script,Boolean.class);
        Boolean result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new FastJsonRedisSerializer(Boolean.class), Collections.singletonList(lockKey),uniqueId);
        printResult(result, successMsg, failMsg);
    }

4. 总结

之所以使用redisTemplate, 是因为不需要关心redis是集群的还是单体的。如果是集群环境, 需要调用JedisCluster来对redis进行操作, 单体的则是使用Jedis来对Redis进行操作。spring 定义了RedisConnection接口来封装了,源码如下:

springboot2使用RedisTemplate开发分布式锁的正确打开_第1张图片

转载于:https://my.oschina.net/u/857431/blog/3022431

你可能感兴趣的:(springboot2使用RedisTemplate开发分布式锁的正确打开)