当前位置:网站首页>Redis 分布式锁 + Lua原子操作
Redis 分布式锁 + Lua原子操作
2022-07-26 21:28:00 【weixin_39505091】
package com.example.demo.redis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.exceptions.JedisNoScriptException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RedisLockUtil {
//分布式锁相关字段
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final Long RELEASE_SUCCESS = 1L;
private static final Long UNLOCK_SUCCESS_CODE = 1L;
private volatile String unlockSha1 = "";
private static final Logger logger = LoggerFactory.getLogger(RedisLockUtil.class);
/** * 通过lua脚本释放锁,来达到释放锁的原子操作 * 判断锁住值是否为当前线程持有,是的话解锁,不是的话解锁失败 */
String UNLOCK_LUA = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
@Autowired
private JedisCluster jedisCluster;
/** * 根据loopTryTime循环重试 * @param lockKey 锁key * @param lockVal 锁值,用于解锁校验 * @param expiryTime 锁过期时间 * @param loopTryTime 获取失败时,循环重试获取锁的时长 * @return 是否获得锁 */
public boolean tryLock(String lockKey, String lockVal, long expiryTime, long loopTryTime){
Long endTime = System.currentTimeMillis() + loopTryTime;
while (System.currentTimeMillis() < endTime){
if (tryGetDistributedLock(lockKey, lockVal, expiryTime)){
return true;
}
}
return false;
}
/** * 尝试获取分布式锁 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */
public Boolean tryGetDistributedLock(String lockKey, String requestId, long expireTime) {
String result = jedisCluster.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/** * 释放分布式锁 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */
public Boolean tryUnLockEval(String lockKey, String requestId) {
Object result = jedisCluster.eval(UNLOCK_LUA, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/** * 释放分布式锁,释放失败最可能是业务执行时间长于lockKey过期时间,应当结合业务场景调整过期时间 * @param lockKey 锁key * @param lockVal 锁值 * @return 是否释放成功 */
public boolean tryUnLockEvalsha(String lockKey, String lockVal){
List<String> keys = new ArrayList<>();
keys.add(lockKey);
List<String> argv = new ArrayList<>();
argv.add(lockVal);
try {
Object result = jedisCluster.evalsha(unlockSha1, keys, argv);
return UNLOCK_SUCCESS_CODE.equals(result);
} catch (JedisNoScriptException e){
//没有脚本缓存时,重新发送缓存
logger.info("try to store script......");
storeScript(lockKey);
Object result = jedisCluster.evalsha(unlockSha1, keys, argv);
return UNLOCK_SUCCESS_CODE.equals(result);
} catch (Exception e){
logger.info(e.getMessage());
return false;
}
}
/** * 由于使用redis集群,因此每个节点都需要各自缓存一份脚本数据 * @param slotKey 用来定位对应的slot的slotKey */
public void storeScript(String slotKey){
if (StringUtils.isEmpty(unlockSha1) || !jedisCluster.scriptExists(unlockSha1, slotKey)){
//redis支持脚本缓存,返回哈希码,后续可以继续用来调用脚本
unlockSha1 = jedisCluster.scriptLoad(UNLOCK_LUA, slotKey);
}
}
}
边栏推荐
- npm, npm中文文档, npm学习使用
- A friend with a monthly salary of 50000 told me that you were just doing chores
- Pytorch squeeze() unsqueeze() 用法
- iptables防止nmap扫描以及binlog实现增量备份
- MPLS基础知识概述
- JS delay execution window.onload
- View绘制流程1-View与Window的关系
- Can you use redis? Then come and learn about redis protocol
- 09.01 深度优先搜索
- 七月集训(第26天) —— 并查集
猜你喜欢

06 cp 命令

Understanding and practice of the trend of Bank of London foreign exchange

Xshell7 personal free download, use

1 - "pytorch deep learning practice" - linear model

Flink's real-time data analysis practice in iFLYTEK AI marketing business

Isilon 的OneFs常见操作命令(一)

TASK04|分类分析

带你搞懂MySQL隔离级别,两个事务同时操作同一行数据会怎样?

仅需一个依赖给Swagger换上新皮肤,既简单又炫酷

Altium designer 22 Chinese character garbled
随机推荐
09 expr command
1 - "pytorch deep learning practice" - linear model
【C语言基础】17 链表初探
06 cp 命令
Jd.com: how does redis realize inventory deduction? How to prevent goods from being oversold?
自己学习Cesium的笔记简介
Task04 | classification analysis
easyui datagrid 获取多条选中的数据进行操作
Implementation of MATLAB short-time autocorrelation
Knowledge base tools | wechat, document center, image display page can be generated by dragging (with template, directly used)
C# 数据类型_摘自菜鸟教程
Triangular wave spectrum of MATLAB excitation model
Flink's real-time data analysis practice in iFLYTEK AI marketing business
Pytorch torch. add() torch. add_ () usage
Xshell7 personal free download, use
ZABBIX calls API retrieval method
基于CAShapeLayer和贝塞尔曲线的圆形进度条动画
Pytorch torch.add() torch.add_() 用法
The principle of normal equation method and its difference from gradient descent method
[RequireComponent(typeof(....))]