首页 > 其他分享 >分布式锁-lua脚本

分布式锁-lua脚本

时间:2023-08-18 16:47:20浏览次数:32  
标签:脚本 return redis Long redisScript lua key new 分布式

// 工具类
@Component public class RedisLock { @Autowired private RedisTemplate redisTemplate; // 时间轮异步定时执行 private HashedWheelTimer timer = new HashedWheelTimer(); private DefaultRedisScript addTimeScript; { DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock.lua"))); this.addTimeScript = redisScript; } /*** * @Description: 获取锁并设置过期时间 * @Author: szc * @Date: 2023/8/15 19:52 * @Params [key, expireSecond] * @Return boolean */ public boolean tryLock(String key, long expireSecond){ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock.lua"))); Long isSuccess = (Long) redisTemplate.execute(redisScript, Arrays.asList(key), expireSecond); return isSuccess != null && isSuccess == 1L; } /*** * @Description: 释放锁,删除key * @Author: szc * @Date: 2023/8/15 19:52 * @Params [key, expireSecond] * @Return boolean */ public boolean unLock(String key){ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_unlock.lua"))); Long isSuccess = (Long) redisTemplate.execute(redisScript, Arrays.asList(key)); return isSuccess != null && isSuccess == 1L; } /*** * @Description: 自增1 * @Author: szc * @Date: 2023/8/15 19:52 * @Params [key, expireSecond] * @Return boolean */ public boolean incrKey(String key, long expireSecond){ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_incr_expire.lua"))); Long isSuccess = (Long) redisTemplate.execute(redisScript, Arrays.asList(key), expireSecond); Object num = redisTemplate.opsForValue().get(key); System.out.println("incrKey========="+num); return isSuccess != null && isSuccess == 1L; } /*** * @Description : key过期前未执行完,自动续期,增加过期时间 * @Author: szc * @Date: 2023/8/15 22:07 * @Params [key, time] * @Return void */ public void addTime(String key, long time) { timer.newTimeout( timerTask -> { //意思就是执行luaaa,key给KEYS[1],time给ARGV[1] Long execute = (Long) redisTemplate.execute(addTimeScript, Arrays.asList(key), time); if (execute == 0) { ThreadUtils.threadInfo("当前key还存在,自动续期。"); addTime(key, time); } else { ThreadUtils.threadInfo("key不存在了,不需要续期"); } }, time / 3, TimeUnit.SECONDS);//time的三分之一时间去执行看有没有key,有重置过期时间,没有就什么都不做。 } }

src\main\resources\redis\redis_incr_expire.lua

-- 每次增加1,设置过期时间
local result = tonumber(redis.call('incr', KEYS[1]))
if(result == 1) then
    redis.call('expire', KEYS[1], ARGV[1])
    return result
else
    return result
end

  src\main\resources\redis\redis_lock.lua

-- 使用中的坑:需要重写redistemplate , 不然返回的都是0
--  eval "return tonumber(redis.call('setnx', 'lock_test', 'lock_test'))" 0     对应下一行执行
local result = tonumber(redis.call('setnx', KEYS[1], ARGV[1]))
if(result == 1) then
    redis.call('expire', KEYS[1], ARGV[1])
    return result
else
    return result
end

 \src\main\resources\redis\redis_unlock.lua

-- 15 为设置的过期时间,可以java参数传递,使用ARGV[1]接收
if(redis.call('get', KEYS[1]) == '15') then
    return redis.call('del', KEYS[1])
else
    return 0
end 

依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

  yml

spring:
  redis:
    host: localhost
    port: 6379
    password:

使用

public class RedisLockController {
    @Autowired
    private RedisLock redisLock;

    @RequestMapping("lock")
    public void lock(){
        long expireSecond = 15;
        String key = "lock_test";
        boolean lock = redisLock.tryLock(key, expireSecond);
        if(lock){
            try {
                // key过期前未执行完,自动续期,增加过期时间
                redisLock.addTime(key,expireSecond);
                log.info("获取锁成功。。。。。。");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                boolean unLock = redisLock.unLock(key);
                if(unLock){
                    log.info("释放锁成功!");
                }else {
                    log.info("释放锁失败!");
                }
            }
        }else {
            log.info("获取锁失败。");
        }

    }
    @RequestMapping("incrKey")
    public void incrKey(){
        redisLock.incrKey("num_test", 60);
    }

  

标签:脚本,return,redis,Long,redisScript,lua,key,new,分布式
From: https://www.cnblogs.com/szc1998/p/17640924.html

相关文章

  • accesskey_tools:一款针对云环境的多功能利用脚本工具
    一、 关于accesskey_tools"accesskey_tools"是一个基于Python开发的多平台云环境利用辅助脚本。该工具可用于渗透测试中,因开发的不规范,以及一些其它漏洞,拿到泄漏AK/SK的情况下,测试人员可以直接利用这些凭证对云服务器进行测试,及时修复风险并采取相应措施,确保云环境中的敏感凭......
  • 【分布式技术专题】「分布式ID系列」百度开源的分布式高性能的唯一ID生成器UidGenerat
    推荐超值课程:点击获取UidGenerator是什么UidGenerator是百度开源的一款分布式高性能的唯一ID生成器,更详细的情况可以查看官网集成文档uid-generator是基于Twitter开源的snowflake算法实现的一款唯一主键生成器(数据库表的主键要求全局唯一是相当重要的)。要求java8及以上版本......
  • 脚本保存
    #!/bin/bash#LoRAtrainscriptby@Akegarasumodifyby@bdsqlsz#TrainModel|训练模式model="sdxl_lora"#lora、db、sdxl_lora、sdxl_db、contralnet(unfinished)#Traindatapath|设置训练用模型、图片pretrained_model="./sd-models/astreapixieXL.safetenso......
  • 使用油猴脚本,自动填写Jira任务
    公司使用Jira作为日常管理,所以Jira填写就比较频繁了,我做了一个示例,剩下的功能就各位自己添加吧//==UserScript==//@nameJira填写//@namespacehttp://tampermonkey.net///@version0.1//@description自动填充,每周填写的任务计划//@author......
  • 1分钟看懂:什么是跨站脚本攻击?
    跨站脚本攻击,又叫XSS攻击。是指:攻击者将恶意脚本代码嵌入到正常用户会访问到的页面中,当正常用户访问该页面时,则可导致嵌入的恶意脚本代码的执行,入侵用户账户,窃取用户信息或执行更具危险性的侵犯行为。XSS攻击有多种攻击类型,其中最为常见、危害最大的就是存储型XSS攻击。举个栗子......
  • 30个shell脚本简单示例
    30个简单且常用的LinuxShell脚本命令及示例,有用~~时代Java 2023-08-1807:40 发表于北京↑ 点击上面 “时代Java”关注我们,关注新技术,学习新知识!shell一直是类Unix系统的本地命令行解释器。它已被证明是Unix的主要功能之一,并发展成为一个全新的主题。Linux提供了各......
  • 分布式事务
    2023.8.17先假设我们有一个订单系统,收到请求之后,我们要干这几件事:1.生成订单2.清空购物车3.生成积分4.1号账户扣款5.2号账户收款 收到请求的服务是A,最慢的办法,我们在这个请求的接口中串行的调用其他服务中的接口,有异常,或者设计好请求的返回(理想情况,都有可以拿到的返回),就......
  • Linux实用运维脚本分享
     编辑Linux实用运维脚本分享......
  • 【问题】分布式事务的场景下如何保证读写分离的数据一致性
    我的理解这个题目可以获得以下关键字:分布式处理、读写分离、数据一致性。那么就从”读写分离“做切入口吧,按我的理解其实就是在保证数据一致性的前提下两个(或以上)的数据库分别肩负不同的数据处理任务。太过久远的就不说了,最近几年其实都用的MySQL比较多。那么就基于MySQL我用......
  • Linux Shell下awk,sed,cut的常用方法并在自动化运维脚本中联合运用
    AWK处理工具,它可以用于提取、处理和格式化文本数据。它的主要功能是逐行扫描文件,并根据匹配模式执行操作。AWK具有以下主要特点:读取和处理文本文件中的数据根据匹配模式执行操作逐行扫描文件打印指定的列在自动化运维脚本中,AWK可以用于处理日志文件,例如提取特定行的数据、从日志文......