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

库存数据redis初始化 redis 库存方案_Java

库存数据redis初始化 redis 库存方案_Java_02

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



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

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执行lua成功,是因为他代码里面配置了RedisTemplate的string序列化,然后才成功的。

库存数据redis初始化 redis 库存方案_spring_03

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



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

库存数据redis初始化 redis 库存方案_lua_04

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