Redis工具组件Lua脚本实现

复制代码
package com.jd.common.core.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import java.util.Collections;
/**
 * <p>Description: 分布式锁RedisLock</p>
 * <p>Copyright: Copyright (c)2,024</p>
 * <p>Company: tope</p>
 * <P>Created Date :2024年02月13日</P>
 * @version 1.0
 */
@Component
public class RedisLock {
    private final static Logger log = LoggerFactory.getLogger(RedisLock.class);
    @Autowired
    RedisTemplate redisTemplate;
    private StringRedisSerializer argsStringSerializer = new StringRedisSerializer();
    private StringRedisSerializer resultStringSerializer = new StringRedisSerializer();
    private final String EXEC_RESULT = "1";

    //定义获取锁的lua脚本
    private final static DefaultRedisScript<String> LOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2]) then "
                    + "return '1' "
                    + "else "
                    + "return '0' "
                    + "end"
            , String.class
    );

    //定义释放锁的lua脚本
    private final static DefaultRedisScript<String> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEYS[1]) == ARGV[1] then "
                    + "return tostring(redis.call('del',KEYS[1])) "
                    + "else "
                    + "return '0' "
                    + "end"
            , String.class
    );

    /**
     * 加锁操作
     * @param key Redis 锁的 key 值
     * @param requestId 请求id,防止解了不该由自己解的锁 (随机生成)
     * @param expireTime 锁的超时时间(毫秒)
     * @param retryTimes 获取锁的重试次数
     * @return true or false
     */
    @SuppressWarnings("unchecked")
    public boolean lock(String key, String requestId, String expireTime, int retryTimes) {
        if (retryTimes <= 0) {
            retryTimes = 1;
        }
        try {
            int count = 0;
            while (true) {
                String result = (String) redisTemplate.execute(LOCK_LUA_SCRIPT, argsStringSerializer, resultStringSerializer,
                        Collections.singletonList(key), requestId, expireTime);
                log.debug("result:{},type:{}", result, result.getClass().getName());
                if (EXEC_RESULT.equals(result)) {
                    log.info("lock---->result:{},requestId:{}", "加锁成功", requestId);
                    return true;
                } else {
                    count++;
                    if (retryTimes == count) {
                        log.warn("has tried {} times , failed to acquire lock for key:{},requestId:{}", count, key, requestId);
                        return false;
                    } else {
                        log.warn("try to acquire lock {} times for key:{},requestId:{}", count, key, requestId);
                        Thread.sleep(100);
                        continue;
                    }
                }
            }
        } catch (InterruptedException e) {
            log.error("lock---->result:{},requestId:{}", "加锁异常", requestId);
        }
        return false;
    }

    /**
     * 解锁操作
     * @param key Redis 锁的 key 值
     * @param requestId 请求 id, 防止解了不该由自己解的锁 (随机生成)
     * @return true or false
     */
    @SuppressWarnings("unchecked")
    public boolean unLock(String key, String requestId) {
        String result = (String) redisTemplate.execute(UNLOCK_LUA_SCRIPT, argsStringSerializer, resultStringSerializer,
                Collections.singletonList(key), requestId);
        if (EXEC_RESULT.equals(result)) {
            log.info("unLock---->result:{},requestId:{}", "解锁成功", requestId);
            return true;
        }
        return false;
    }

}
相关推荐
ACP广源盛139246256731 小时前
Qwen3.8‑2.4T 开源落地@ACP#国产 MoE 大模型私有化部署中 MST 多屏转换芯片 GSV2231 硬件价值与应用场景
大数据·数据库·人工智能·嵌入式硬件
java_logo1 小时前
Docker 部署 openGauss:轻松搭建企业级开源关系型数据库平台
数据库·docker·开源·opengauss·轩辕镜像·opengauss部署教程·opengauss部署文档
旺仔学长 哈哈1 小时前
52486|高校专业评估不再靠表格:Spring Boot 本科专业质量评估管理系统实战
数据库·spring boot·毕业设计·教育管理
梦想的旅途22 小时前
企业微信Webhook回调怎么做自动回复和AI客服
数据库·机器人·自动化·企业微信·rpa
Zguigo2 小时前
OCR 核心原理 + 模型 + 检测与识别
数据库·ocr
凤山老林2 小时前
零停机数据库演进:Spring Boot 集成 Flyway 与平滑DDL变更策略
数据库·spring boot·后端
曹牧3 小时前
Oracle:取固定分隔符字符串中第一个元素
数据库·oracle
szarron3 小时前
VNA6 便携式矢量网络分析仪:从入门到精通
数据库·嵌入式硬件·测试工具·5g·射频工程
临床数据科学和人工智能兴趣组3 小时前
R语言中,列表是一种非常灵活的数据结构,它可以存储不同类型的对象,如向量、矩阵、数据框、甚至其他列表
数据结构·数据库·r语言·r语言-4.2.1·临床试验
cmes_love3 小时前
期货五档Level2行情数据和分钟历史行情数据下载分析
数据库