SpringBoot 中使用Lua编写Redis脚本

Lua是一种编程语言,它的基本语法大家可以参考网站:Lua 教程 | 菜鸟教程

1.什么是Lua

LUA 是一种轻量级、可扩展的脚本编程语言,以其小巧、快速、灵活和易于嵌入到宿主应用程序中的特性而闻名。

轻量级:小巧的解释器,占用资源少,适用于嵌入式环境和资源受限系统。 动态类型:支持动态类型,变量无需事先声明类型,运行时自动识别。 可扩展:通过 C API 易于与宿主程序集成,提供丰富的扩展机制,便于构建定制化功能。 面向过程与函数式:支持函数作为第一类值,具备高阶函数、闭包等特性,适合函数式编程风格。 协程(Coroutine):内置协程支持,实现非阻塞的并发编程,适用于异步任务与事件处理。 简洁易学:语法简单清晰,学习曲线平缓,代码易于阅读和编写。 高效执行:解释器经过优化,执行速度快,尤其在脚本语言中表现出色。 跨平台:用 C 语言编写,高度可移植,能在多种操作系统和硬件架构上运行。 广泛应用:广泛应用于游戏开发、配置脚本、科学计算、网络服务等领域,作为嵌入式脚本语言尤为出色。

我们在这里用它是因为Lua脚本执行Redis是因为它是原子性的,可以保证一整段脚本是一个事务,然后如果有需求它也可以很好的实现异步任务

2.准备工作

  • IDEA安装插件

3.使用

  • 3.1 编写Lua脚本

    放在resources目录下

    只是个例子,具体脚本可以根据需求和参考网址编写你自己的业务脚本

    ---
    --- Generated by Luanalysis
    --- Created by orz.
    --- DateTime: 2024/4/23 20:25
    ---
    -- 1.参数列表
    -- 1.1.优惠券id
    local voucherId = ARGV[1]
    -- 1.2.用户id
    local userId = ARGV[2]
    -- 1.3.订单id
    local orderId = ARGV[3]
    
    -- 2.数据key
    -- 2.1.库存key
    local stockKey = 'seckill:stock:' .. voucherId
    -- 2.2.订单key
    local orderKey = 'seckill:order:' .. voucherId
    
    -- 3.脚本业务
    -- 3.1.判断库存是否充足 get stockKey
    if(tonumber(redis.call('get', stockKey)) <= 0) then
        -- 3.2.库存不足,返回1
        return 1
    end
    -- 3.2.判断用户是否下单 SISMEMBER orderKey userId
    if(redis.call('sismember', orderKey, userId) == 1) then
        -- 3.3.存在,说明是重复下单,返回2
        return 2
    end
    -- 3.4.扣库存 incrby stockKey -1
    redis.call('incrby', stockKey, -1)
    -- 3.5.下单(保存用户)sadd orderKey userId
    redis.call('sadd', orderKey, userId)
    -- 3.6.发送消息到队列中, XADD stream.orders * k1 v1 k2 v2 ...
    redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId)
    return 0

  • 3.2 ServiceImpl业务中使用
    //DefaultRedisScript 是 Spring Data Redis 框架提供的一个类,用于简化在 Spring 应用程序中使用 Redis 脚本(如Lua脚本)的过程
    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
    //脚本静态代码块初始化
    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        //在resources目录下导入我们的脚本文件
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    执行脚本的方法

    @Override
    public Result seckillVoucher(Long voucherId) {
        //获取用户
        Long userId = UserHolder.getUser().getId();
        long orderId = redisIdWorker.nextId("order");
        // 1.执行lua脚本(要传三部分参数)
        //stringRedisTemplate.execute(),该方法就是用来执行Redis脚本
        //第一部分:RedisScript: 包含待执行脚本内容及返回值类型的对象。
        //第二部分:keys: 与脚本关联的键列表,可在脚本中通过 KEYS 访问。
        //第三部分:args: 传递给脚本的额外参数数组,可在脚本中通过 ARGV 访问。
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,//这里就是我们上面静态代码块引入的脚步
                Collections.emptyList(),
            //这里要传key类型的参数,因为我上面写入redis缓存的key是用下面的第三部分参数args来拼出来的,
            //所以脚本是不需要key的,所以这里用方法传一个空集合,注意不要传null
                voucherId.toString(), userId.toString(), String.valueOf(orderId)
            //上面第三部分要传的参数取决于我们脚本的ARGV[]数量
        );
        //根据脚本的返回值result.intValue()来进行下一步的逻辑
        int r = result.intValue();
        // 2.判断结果是否为0
        if (r != 0) {
            // 2.1.不为0 ,代表没有购买资格
            return Result.fail(r == 1 ? "库存不足" : "不能重复下单");
        }
        //TODO 保存阻塞队列
        // 3.返回订单id
        return Result.ok(orderId);
    }

  • 35
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值