Redis 分布式锁

Redis 分布式锁

Redis的setnx命令是当key不存在时设置key,但setnx不能同时完成expire设置失效时长,不能保证setnx和expire的原子性。我们可以使用set命令完成setnx和expire的操作,并且这种操作是原子操作。
下面是set命令的可选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
set key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds:设置失效时长,单位秒
PX milliseconds:设置失效时长,单位毫秒
NX:key不存在时设置value,成功返回OK,失败返回(nil)
XX:key存在时设置value,成功返回OK,失败返回(nil)

案例:设置name=p7+,失效时长100s,不存在时设置
1.1.1.1:6379> set name p7+ ex 100 nx
OK
1.1.1.1:6379> get name
"p7+"
1.1.1.1:6379> ttl name
(integer) 94

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 分布式锁
*
* @author zc
* @date 2020/9/15 11:17
*/
@Slf4j
@Service
public class DistributedLockService {

@Autowired
RedisTemplate<String, Object> redisTemplate;

/**
* 加锁
*
* @param key 键
* @param value 值
* @return 返回值
*/
private Boolean lock(String key, Object value) {
return redisTemplate.opsForValue().setIfAbsent(key, value, 10, TimeUnit.SECONDS);
}

/**
* 解锁
*
* @param key 键
* @return 返回值
*/
private Boolean unLock(String key) {
return redisTemplate.delete(key);
}

public Long incr(String key) {
return redisTemplate.opsForValue().increment(key, 1);
}

public Long distributedLock(String goodsId) {
int i = 1;
while (true) {
log.info(goodsId + "," + i++);
if (this.lock(goodsId, goodsId)) {
Long l = this.incr("incr_" + goodsId);
log.info("递增数量:{}", l);
this.unLock(goodsId);
return l;
}
}
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Slf4j
@SpringBootTest
class RedisDistributedLockServiceApplicationTests {

@Autowired
DistributedLockService distributedLockService;

@Test
void redisDistributedLock() throws InterruptedException {
for (int i = 0; i < 10; i++) {
int a = i;
Thread thread = new Thread("lock") {
@Override
public void run() {
log.info("DistributedLock: {}", distributedLockService.distributedLock("goodsId"));
}
};
thread.start();
}
Thread.sleep(20000);
}
}


Redis 分布式锁
https://happyloves.cn/20220831/194fe3fc2cd2.html
作者
赵小胖
发布于
2022年8月31日
许可协议