Description
简要描述
RedisTemplateSimpleDistributedLock 在trylock和unlock 中针对Key的序列化方式不一致导致无法正确释放锁的问题。
模块版本情况
- WxJava 模块名: weixin-java-cp
- WxJava 版本号: 4.7.6.B
详细描述
在使用Redis的分布式锁的场景下,WxCpRedisTemplateConfigImpl
类需要注入StringRedisTemplate
类,当我的StringRedisTemplate
添加了自定义的Key序列化处理的时候, 比如统一对Key加上前缀 System: ,会导致分布式锁无法正常释放。
在RedisTemplateSimpleDistributedLock
类中的trylock
方法如下
@Override
public boolean tryLock() {
String value = valueThreadLocal.get();
if (value == null || value.isEmpty()) {
value = UUID.randomUUID().toString();
valueThreadLocal.set(value);
}
final byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
final byte[] valueBytes = value.getBytes(StandardCharsets.UTF_8);
List<Object> redisResults = redisTemplate.executePipelined((RedisCallback<String>) connection -> {
connection.set(keyBytes, valueBytes, Expiration.milliseconds(leaseMilliseconds), RedisStringCommands.SetOption.SET_IF_ABSENT);
connection.get(keyBytes);
return null;
});
Object currentLockSecret = redisResults.size() > 1 ? redisResults.get(1) : redisResults.get(0);
return currentLockSecret != null && currentLockSecret.toString().equals(value);
}
如上设置key使用的是Redis的底层 RedisConnection
类直接处理的,会导致StringRedisTemplate类的Key的前缀无法加上
比如Key为 wechat_cp_lock:ww948:1000010:accessToken 无法加上System: 为 System:wechatt_cp_lock:ww948****:1000010:accessToken
但是在unlock的代码中:
@Override
public void unlock() {
if (valueThreadLocal.get() != null) {
// 提示: 必须指定returnType, 类型: 此处必须为Long, 不能是Integer
RedisScript<Long> script = new DefaultRedisScript<>("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
redisTemplate.execute(script, Collections.singletonList(key), valueThreadLocal.get());
valueThreadLocal.remove();
}
}
如上使用的却是redisTemplate
设置处理redis的Key的导致。
从而导致的问题就是 trylock实际设置的Key是 wechatt_cp_lock:ww948:1000010:accessToken
但是释放的时候 所使用的Key是System:wechatt_cp_lock:ww948:1000010:accessToken
导致无法释放的问题。
日志
如果日志不多,直接使用md代码引用格式贴在此处,否则如果太长,请将日志放在 [pastebin](https://paste.ubuntu.com/) 或者其他地方,然后将其url地址贴在这里
日志请写于此处