Redis Lock

源码

/**
    * @param key           redis key, 唯一键
    * @param value         redis value, 这里是时间戳
    * @return
    * @desc 加锁 true已锁  false未锁
    */
private boolean lock(String key, String value) {
    if(redisTemplate.opsForValue().setIfAbsent(key, value, 5, TimeUnit.MINUTES)) { // 对应setnx命令
        //可以成功设置,也就是key不存在
        return true;
    }
    // 判断锁超时 - 防止原来的操作异常,没有运行解锁操作  防止死锁
    String currentValue = (String) redisTemplate.opsForValue().get(key);
    // 如果锁过期
    // currentValue 不为空且小于当前时间
    if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
        // 获取上一个锁的时间value
        // 对应getset,如果key存在返回当前key的值,并重新设置新的值
        // redis是单线程处理,即使并发存在,这里的getAndSet也是单个执行
        // 所以,加上下面的 !StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)
        // 就能轻松解决并发问题
        String oldValue = (String) redisTemplate.opsForValue().getAndSet(key,value);
        if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
            return true;
        }
    }
    return false;
}

/**
    * @param key           redis key, 唯一键
    * @param value         redis value, 这里是时间戳
    * @return
    * @desc 释放锁 true已释放  false未释放
    */
private void unlock(String key, String value) {
    try {
        String currentValue = (String) redisTemplate.opsForValue().get(key);
        if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
            redisTemplate.opsForValue().getOperations().delete(key);// 删除key
        }
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
}
  

参考

  1. springboot2.1.3 + redisTemplate + Lock 操作 redis 3.0.5
  2. RedisTemplate 事务处理方法 watch multi exec 的使用