实现基于Redis的lua的分布式锁

发布 : 2019-05-10 分类 : Redis 浏览 :

代码如下

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.ym.common.utils.redis;

import com.ym.common.utils.Sha1Util;
import com.ym.common.utils.spring.SpringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Collections;

/**
* 基于redis lua分布式锁
*
* @author: 李涛
* @version: 2019年05月08日 16:15
*/
public class RedisLockUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockUtil.class);

/**
* 成功标识
*/
private static final Long SUCCESS = 1L;

/**
* 加锁lua脚本,不可重入,reqId只是为了解锁使用,代表当前线程在使用资源,给UUID比较好
*/
private static final String SCRIPT_LOCK = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then redis.call('pexpire', KEYS[1], ARGV[2]) return 1 else return 0 end";

/**
* 解锁lua脚本
*/
private static final String SCRIPT_UNLOCK = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

/**
* 加锁脚本sha1值
*/
private static final String SCRIPT_LOCK_SHA1 = Sha1Util.encrypt(SCRIPT_LOCK);

/**
* 解锁脚本sha1值
*/
private static final String SCRIPT_UNLOCK_SHA1 = Sha1Util.encrypt(SCRIPT_UNLOCK);

/**
* 内部持有模板
*/
private static final RedisTemplate redisTemplate = (RedisTemplate) SpringUtil.getObject("redisTemplate");

/**
* 尝试获取分布式锁
*
* @param lockKey 锁
* @param requestId 请求标识,唯一ID
* @param expireTimeMilliseconds 超期时间,多少毫秒后这把锁自动释放
* @return 返回true表示拿到锁
*/
public static boolean tryGetDistributedLock(String lockKey, String requestId, int expireTimeMilliseconds) {
LOGGER.info("[{}]尝试获取[{}]锁,超时时间为:{}毫秒", requestId, lockKey, expireTimeMilliseconds);
/**
* 脚本设置
*/
RedisScript<Long> redisScript = new RedisScript<Long>() {
@Override
public String getSha1() {
return SCRIPT_LOCK_SHA1;
}

@Override
public Class<Long> getResultType() {
return Long.class;
}

@Override
public String getScriptAsString() {
return SCRIPT_LOCK;
}

};
Object result = redisTemplate.execute(
redisScript,// lua脚本
Collections.singletonList(lockKey),// KEYS[1]
requestId, // ARGV[1]
expireTimeMilliseconds // ARGV[2]
);
boolean b = SUCCESS.equals(result);
LOGGER.info("释放结果:", b);
return b;
}

/**
* 释放分布式锁
*
* @param lockKey 锁
* @param requestId 请求标识
* @return 返回true表示释放锁成功
*/
public static boolean releaseDistributedLock(String lockKey, String requestId) {
LOGGER.info("[{}]释放锁[{}]锁", requestId, lockKey);

/**
* lua脚本
*/
RedisScript<Long> redisScript = new RedisScript<Long>() {
@Override
public String getSha1() {
return SCRIPT_UNLOCK_SHA1;
}

@Override
public Class<Long> getResultType() {
return Long.class;
}

@Override
public String getScriptAsString() {
return SCRIPT_UNLOCK;
}

};
Object result = redisTemplate.execute(
redisScript,
Collections.singletonList(lockKey),
requestId
);
boolean b = SUCCESS.equals(result);
LOGGER.info("释放结果:", b);
return b;
}
}
本文作者 : 625
原文链接 : https://www.kanchai.club/625/2019/05/10/实现基于Redis的lua的分布式锁/
版权声明 : 本博客所有内容均供学习交流使用,转载请注明出处哦!

缺一盒火柴点火

微信扫一扫, 向我投食

微信扫一扫, 向我投食

支付宝扫一扫, 向我投食

支付宝扫一扫, 向我投食

留下足迹