如何使用
在分布式或者多线程操作Redis时,使用redisson会很方便,也有一些问题要注意。
在一个分布式环境运行的方法中,RLock的一般使用情况:
String lockKey = "abc"; //指定一个锁名称
RLock rLock = redissonClient.getLock(lockKey); //获取一个锁
try {
rLock.lock(); //加锁
} finally {
rLock.unlock(); //解锁
}
这里lockKey的值是"abc",redisson会在redis中存一个以"abc"为键的hash类型的值:
> type lock
hash
简单的情况下,里面的内容:
> hgetall lock
1) "25bea362-174c-4e31-aaab-046e3d138c2e:64"
2) "1"
解释:
"25bea362-174c-4e31-aaab-046e3d138c2e:64":这是hash
字段的键,表示这个分布式锁的名称。25bea362-174c-4e31-aaab-046e3d138c2e
是 Redisson 内部生成的一个唯一标识符,而64
是 Redis 分区信息。
"1":这是hash
字段的值,表示该分布式锁在 Redis 中处于锁定状态。Redis 使用字段的值来记录锁的状态,通常将其设置为1
表示锁定状态,当锁被释放时,字段的值会被删除或者设置为其他值。
如果在不知道"abc"类型的情况下,当做string来查询:
> get abc
(error) WRONGTYPE Operation against a key holding the wrong kind of value
在锁释放以后再来查询会得到:
> hgetall lock
(empty list or set)
可能的报错场景
字段使用冲突场景:
String lockKey = "abc"; //锁名称
String redisKey = "abc"; //redis的key
RLock rLock = redissonClient.getLock(lockKey);
try {
rLock.lock();
// 业务
} finally {
rLock.unlock();
}
报错可能是这样的:
ERR Error running script (call to f_3ffe249c16dee540ac8ab32e39bd408626b9aff7):
@user_script:1: WRONGTYPE Operation against a key holding the wrong kind of value .
channel: [id: 0x67a075d9, L:/127.0.0.1:14028 - R:localhost/127.0.0.1:6379]
command: (EVAL), promise: java.util.concurrent.CompletableFuture@5f77df46[Not completed],
params: [if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil;end; local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]);
return 0; else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; return nil;,
2, lock, redisson_lock__channel:{lock}, 0, 30000, 76ffcf49-9bee-4fdc-a4bc-3ddaa918636b:64]
修改后不报错:
/**
两个不能一样
*/
String lockKey = "abc"; //锁名称
String redisKey = "abcd"; //redis的key
RLock rLock = redissonClient.getLock(lockKey);
try {
rLock.lock();
// 业务
} finally {
rLock.unlock();
}
原因就是redisson会在redis中存一个以"abc"为键的hash类型的值,如果abc已经存在,就会加锁不成功,类型也不匹配。实际业务中多会使用业务的id或者name来给redis或者redisson锁的名称来命名,还是要注意这一点。