springboot升级到2.0之后,关联的spring-data-redis默认使用的连接包也从原本的jedis改为了性能更好,且线程安全的使用netty实现的lettuce连接包。
鉴于spring-data默认只提供了setnx不带过期时间的入口,为了防止分布式锁的死锁只能自己来实现setnx关键词
以下是使用默认的stringRedisTemplate实现setnx的过程:
/**
* @param key key值
* @param value value值
* @param expiredTime 过期时间(秒)
* @return
*/
private boolean setNx(String key, String value, long expiredTime) {
Boolean resultBoolean = null;
try {
resultBoolean = stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> {
Object nativeConnection = connection.getNativeConnection();
String redisResult = "";
@SuppressWarnings("unchecked")
RedisSerializer<String> stringRedisSerializer = (RedisSerializer<String>) stringRedisTemplate.getKeySerializer();
//lettuce连接包下序列化键值,否知无法用默认的ByteArrayCodec解析
byte[] keyByte = stringRedisSerializer.serialize(key);
byte[] valueByte = stringRedisSerializer.serialize(value);
// lettuce连接包下 redis 单机模式setnx
if (nativeConnection instanceof RedisAsyncCommands) {
RedisAsyncCommands commands = (RedisAsyncCommands)nativeConnection;
//同步方法执行、setnx禁止异步
redisResult = commands
.getStatefulConnection()
.sync()
.set(keyByte, valueByte, SetArgs.Builder.nx().ex(10));
}
// lettuce连接包下 redis 集群模式setnx
if (nativeConnection instanceof RedisAdvancedClusterAsyncCommands) {
RedisAdvancedClusterAsyncCommands clusterAsyncCommands = (RedisAdvancedClusterAsyncCommands) nativeConnection;
redisResult = clusterAsyncCommands
.getStatefulConnection()
.sync()
.set(keyByte, valueByte, SetArgs.Builder.nx().ex(10));
}
//返回加锁结果
return "OK".equalsIgnoreCase(redisResult);
});
} catch (Exception e) {
e.printStackTrace();
}
return resultBoolean != null && resultBoolean;
}
注意:可以使用默认的del方法来释放锁,因为key已经使用默认的key序列化器进行了序列化。
如果使用jedis连接器del方法也需要自己来实现