Lua脚本操作redis

模拟库存扣减

基础版

java 复制代码
@SpringBootTest
class LuaTests {


    @Resource(name="redisTemplate")
    ValueOperations<String,Long> valueOperations;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    final  String priductKey = "product.1";


    @Test
    void test1() throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append(" local key = KEYS[1] ");
        sb.append(" local qty = ARGV[1] ");
        sb.append(" local redis_qty = redis.call('get',key) ");
        sb.append(" if tonumber(redis_qty) >= tonumber(qty)  then ");
        sb.append("   redis.call('decrby',key,qty) ");
        sb.append("  return  -1 "); // -1 代表的扣减成功了
        sb.append(" else ");
        sb.append("  return tonumber(redis_qty)  "); //返回的当前的库存量 , 0,1,2 .......
        sb.append(" end ");
        RedisScript<Long>  script =  RedisScript.of(sb.toString(),Long.class);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            executorService.execute(()->{
               int needQty = RandomUtil.randomInt(1,5);
                Long qty = stringRedisTemplate.execute(script, CollUtil.newArrayList(priductKey), needQty + "");
                if(qty == -1 ){
                    System.out.println(StrUtil.format("{} 扣减成功,需求量是:{}",Thread.currentThread().getId(),needQty));
                } else {
                    System.out.println(StrUtil.format("{} 扣减失败,您的需求量是:{},当前库存量是:{}",Thread.currentThread().getId(),needQty,qty));
                }
            });

        }

     System.in.read();
    }

升级版

java 复制代码
@Test
    void test2() throws IOException {
        final String key1 = "product.1";
        final String key2 = "product.2";
        final String key3 = "product.3";
        valueOperations.set(key1,5l);
        valueOperations.set(key2,10l);
        valueOperations.set(key3,15l);
        StringBuilder sb = new StringBuilder();
        sb.append(" local table = {} ");
        sb.append(" local redis_qtys =  redis.call('mget',unpack(KEYS)) ");
        sb.append(" for i=1, #KEYS do ");
        sb.append("  if  tonumber(ARGV[i]) >  tonumber(redis_qtys[i]) then");
        sb.append("   table[#table + 1] = KEYS[i] .. '=' .. redis_qtys[i]  "); // product.2=56
        sb.append("  end ");
        sb.append(" end ");

        sb.append(" if #table > 0  then "); //如果有任何一个商品库存不足
        sb.append("  return table ");
        sb.append(" end ");
        //能够走到这一行
        sb.append(" for i=1, #KEYS do ");
        sb.append("  redis.call('decrby',KEYS[i],ARGV[i]) ");
        sb.append(" end ");
        sb.append(" return {} ");
        RedisScript<List>  script =  RedisScript.of(sb.toString(),List.class);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 1; i++) {
            executorService.execute(()->{
                int needQty1 = RandomUtil.randomInt(1,7);
                int needQty2 = RandomUtil.randomInt(1,10);
                int needQty3 = RandomUtil.randomInt(1,16);
                List ret = stringRedisTemplate.execute(script, CollUtil.newArrayList(key1,key2,key3), needQty1+"",needQty2+"",needQty3+"");
                if(ret.size() == 0 ){
                    System.out.println(StrUtil.format("{} 扣减成功,需求量是:{},{},{}",Thread.currentThread().getId(),needQty1,needQty2,needQty3));
                } else {

                    System.out.println(StrUtil.format("{} 扣减失败,您的需求量是:{},{},{} ",Thread.currentThread().getId(),needQty1,needQty2,needQty3));
                   for(Object obj :ret){
                       System.out.println(obj);
                   }
                }
            });

        }

        System.in.read();
    }
相关推荐
momo061178 小时前
Redis新手入门 -- 学习笔记
redis·后端
吃饱了得干活16 小时前
Redisson 进阶实战:看门狗机制与分布式锁完全指南
java·redis·后端
我是苏苏18 小时前
Redis开发09:Windows系统下主从复制的配置教程
数据库·redis·缓存
写后端的胖头鱼20 小时前
【高频面试题】如何找出redis中的慢查询记录
redis·慢日志
彧azz1 天前
Redis 全面指南:从核心概念到高可用架构实战
数据库·redis·架构
香菜TTT1 天前
Redis的哨兵机制
java·数据库·redis
hweiyu001 天前
Redis命令:APPEND
redis·缓存
敲代码的嘎仔1 天前
从集群锁失效到异步领券:我用分布式锁 + Redisson + MQ 把领券接口 RT 从 200ms 压到 15ms
java·数据库·redis·分布式·缓存·ai·wpf
莫得感情 o2 天前
Redis 12 · 缓存一致性:数据库与缓存双写怎么不乱
redis·缓存
吃饱了得干活2 天前
Spring Boot + Redis 分布式锁:一个订单重复提交引发的六次迭代
java·redis·后端