[Redisson] 如何使用redisson的锁?

发布时间 2023-07-20 10:58:58作者: NetUSA

如何使用

在分布式或者多线程操作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锁的名称来命名,还是要注意这一点。