springboot lua检查redis库存

需求

最近需求需要实现检查多个马戏场次下的座位等席对应库存渠道的库存余量,考虑到性能,决定采用Lua脚本实现库存检查。

数据结构

  • 库存层级结构
  • redis库存hash类型结构

实现

  • lua脚本
lua 复制代码
--- 字符串分割为数组
local function split(str, char)
    local arr = {};
    local pattern = string.format('([^%s]+)', char);
    for item in string.gmatch(str, pattern) do
        table.insert(arr, item);
    end
    return arr;
end
--- 数组转成map
local function toMap(tb)
    if (tb == nil) then
        return {};
    end
    local map = {};
    for i = 1, #tb do
        if (i % 2 == 1) then
            map[tb[i]] = tb[i+1];
        end
    end
    return map;
end
--- 初始化数据,入参01:1,02:2.01:3
local argArr = {};
for rowItem in string.gmatch(ARGV[1], '([^.]+)') do
    local row = {};
    for keyVal in string.gmatch(rowItem, '([^,]+)') do
    -- 解析出每个key与value
        local tempArr = split(keyVal, ':');
        row[tempArr[1]] = tempArr[2];
    end
    table.insert(argArr, row);
end
--- 检查库存
for i = 1, #KEYS do
    --local rData = redis.call("HMGET", KEYS[i], '01 02');
    local rdsMap = toMap(redis.call("HGETALL", KEYS[i]));
    for tier, quantity in pairs(argArr[i]) do
        --redis.log(redis.LOG_NOTICE, string.format('key is:%s,tier is:%s,quantity is:%s', KEYS[i], tier, quantity));
        if (rdsMap[tier] == nil or tonumber(quantity) > tonumber(rdsMap[tier])) then
            return string.format("库存key:%s,tier:%s不足", KEYS[i], tier);
        end
    end
end
return '';

遍历键值对时需要使用pairs而不是ipairs,二者区别如下:

for k,v in pairs(argArr)的遍历顺序并非是table类型数据的排列顺序,而是根据table中key的hash值排列的顺序来遍历的。

for k,v in ipairs(argArr)必须要求table中的key为有序的,而且必须是从1开始,ipairs只会从1开始按连续的key顺序遍历到key不连续为止。

  • 入参设计
    由于RedisTemplate直接传入集合为参数序列化后会有中括号,而lua脚本table类型使用花括号定义,因此采用字符串作为入参,在lua脚本中解析字符串为table类型。例如参数01:1,02:2.01:3代表二维数组,第一行为01:1,02:2,其中01为渠道,1为渠道对应的库存,英文逗号作为渠道分隔符。
  • springboot调用lua脚本
java 复制代码
@Autowired
private StringRedisTemplate redisJsonTemplate;

@Test
public void checkInventory() {
    List<String> keyList = List.of("stock:GZ7:433680411156197407", "stock:GZ7:433680411156197408");
    // 执行 lua 脚本
    DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
    // 指定 lua 脚本
    redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/TheaterStockCheck.lua")));
    // 指定返回类型
    redisScript.setResultType(String.class);
    Object result = redisJsonTemplate.execute(redisScript, keyList, "01:1,0101:2.01:3");
    //01:1,02:2.01:3
    System.out.println(result);
}

调用lua脚本需要使用string序列化方式,使用jdk序列化方式会导致序列化后的数据lua脚本无法解析

  • 测试效果
    • redis库存数据
    • 调用效果
相关推荐
彭于晏Yan5 小时前
MQTT消息服务
spring boot·后端·中间件
indexsunny5 小时前
互联网大厂Java面试实战:从Spring Boot到微服务架构的深度解析
java·spring boot·spring cloud·kafka·prometheus·security·microservices
java1234_小锋5 小时前
分享一套优质的SpringBoot+Vue咖啡商城系统
vue.js·spring boot·咖啡商城
haixingtianxinghai6 小时前
Redis真的是单线程吗?
数据库·redis·缓存
悟空码字6 小时前
滑块拼图验证:SpringBoot完整实现+轨迹验证+Redis分布式方案
java·spring boot·后端
小江的记录本7 小时前
【MyBatis-Plus】Spring Boot + MyBatis-Plus 进行各种数据库操作(附完整 CRUD 项目代码示例)
java·前端·数据库·spring boot·后端·sql·mybatis
码界奇点7 小时前
基于Spring Boot的医院药品管理系统设计与实现
java·spring boot·后端·车载系统·毕业设计·源代码管理
海南java第二人8 小时前
Cursor 高级实战:从 Spring Boot 到微服务,AI 驱动的全流程开发指南
人工智能·spring boot·微服务
爱笑的源码基地8 小时前
门诊his系统源码,中西医结合的数字化门诊解决方案
java·spring boot·源码·二次开发·门诊系统·云诊所系统·诊所软件源码
庞轩px8 小时前
缓存Key设计的“七要七不要”
java·jvm·redis·缓存