【LUA】如何借助redis的lua功能实现库存扣减

强调:当你打算在本地测试redis的某个功能的时候,你必须保证你本地的springboot版本、redis版本(两个:pom中引入的依赖版本,本地redis-ser的版本)和你公司项目中的版本保持一致。因为不同版本,差别挺大的,往往可能因为版本问题导致两种不同的结果。

2c998c83dfcb46efa99551a5d5356c85.jpeg

759fdb39d35e4e17a2e7e2e96437bedb.jpeg

我们在使用redis的lua脚本功能来实现库存扣减,可以先参考下面的博客:

基于redis实现的扣减库存_JackieZhengChina的博客-CSDN博客_redis减库存

首先,该博客代码是完全可以实现扣减库存的。其次有个坑需要留意一下:

1、博客只字未提springboot的版本。我是下载了源码,然后看了一下springboot的版本发现1.5.13.RELEASE的版本,该版本默认的redis客户端连接是jedis;所以使用这个版本来测试功能是没有问题的;  但是,现在springboot最新版本是2.7的了,而springboot2.x以上版本,默认的redis客户端是lettuce, 导致的结果是,你上面的代码总是执行失败,原因是代码都是对jedis进行判断而没有对lettuce进行判断。

解决方式:(代码不需要动,只需要动pom)

a:代码不做修改,把springboot2.x以上的版本降低到2.x以下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.13.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cms</groupId>
    <artifactId>stock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-stock</name>
    <description>redis-stock</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        // springboot2.x以下,默认已经导入该依赖
        //</dependency>
        //<dependency>
        //    <groupId>redis.clients</groupId>
        //    <artifactId>jedis</artifactId>
        //</dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

--不推荐,因为大部分公司使用的是2.x以上的版本了,不能因为你这个需求降低版本。

b:代码不做修改,springboot2.x不动,修改默认的redis客户端(将lettuce依赖排除,那么就会使用jedis依赖)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cms</groupId>
    <artifactId>stock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-stock</name>
    <description>redis-stock</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
            <version>2.1.12.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

--不推荐。因为有的公司就是使用lettuce作为默认redis的客户端。

总结:

虽然上面博客的代码可行,但是不建议使用。

建议使用StringRedisTemplate来执行lua脚本,好处是我不需要考虑我的redis客户端到底是使用jedis还是lettuce(换言之,我不需要考虑springboot的版本)。

---注意:此处说使用的是StringRedisTemplate,不要用RedisTemplate。因为由于他俩序列化的方式不同,导致一模一样的lua脚本,StringRedisTemplate可能执行成功而RedisTemplate执行不成功。比如:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cms</groupId>
    <artifactId>stock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-stock</name>
    <description>redis-stock</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
            <version>2.1.12.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
private String subStock="local key=KEYS[1];\n" +
            "local subNum = tonumber(ARGV[1]) ;\n" +
            "local surplusStock = tonumber(redis.call('get',key));\n" +
            "if (surplusStock<=0) then return 0\n" +
            "elseif (subNum > surplusStock) then  return 1\n" +
            "else\n" +
            "    redis.call('incrby', KEYS[1], -subNum)\n" +
            "    return 2 \n" +
            "end";
    public Long test(String ipAmountKey, Long initAmountValue, Long reduceAmountValue){
        //构建redisScript对象,构造方法参数1 执行的lua脚本   参数2 结果返回类型
        DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>(subStock,Long.class);
        //参数1 redisScript对象  参数2 keys,可以是多个,取决于你lua里的业务, 参数3 args 需要给lua传入的参数 也是多个
        Long result = (Long) stringRedisTemplate.execute(defaultRedisScript, Arrays.asList("seckillStock:1594778100813"), "10");
// 执行失败
//Long result = (Long) redisTemplate.execute(defaultRedisScript, //Arrays.asList("seckillStock:1594778100813"), "10");
        return result;
    }

究其根本原因:大概率是RedisTemplate默认是jdk的序列化方式,而StringRedisTemplate默认是string的序列化方式:RedisTemplate和StringRedisTemplate的区别_大海会笑的博客-CSDN博客_stringredistemplate

再来参考这篇文章(我并未自己尝试):使用RedisTemplate执行lua脚本_Avogrado的博客-CSDN博客_redistemplate执行lua脚本

这篇文章可以使用RedisTemplate执行lua成功,是因为他代码里面配置了RedisTemplate的string序列化,然后才成功的。

8c2190abd73c4da8869ec44390d1f319.png

再来看这篇文章(我并未自己尝试):

RedisTemplate使用lua脚本_字节抖动的博客-CSDN博客_redistemplate执行lua脚本

这篇文章可以使用RedisTemplate执行lua成功,是因为以文件的形式读取lua脚本。

1d17f71d010c48f680257f5be1d891aa.png

可参考的lua-初始化库存、操作库存:

】Redis+Lua脚本实现商品库存扣减_初夏的晴天的博客-CSDN博客_lua脚本扣减库存【

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@来杯咖啡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值