redistemplate 使用lua脚本

redistemplate 使用lua脚本

依赖
        <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>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
注意事项

springboot使用RedisTemplate操作lua脚本的使用需要配置lettuce客户端,jedis是不支持的,现在springboot也默认是lettuce

spring:
  redis:
    cluster:
      nodes: 192.168.101.98:2001,192.168.101.98:2002,192.168.101.98:2003,192.168.101.98:2004,192.168.101.98:2005,192.168.101.98:2006
    lettuce:
      pool:
        min-idle: 8
        max-idle: 16
        max-active: 16
        max-wait: 10000
案例一

如果不是用复杂的数据类型,用StringRedisTemplate就可以了,里面默认定义了序列化的方式,如果使用集群的reids,

需要保证key在同一个slot,可以用{xx}强制hash

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 抢红包
     * 用户id  红包id
     * @param userId
     * @param redEnvelopeId
     * @return
     */
    @Override
    public String grabRedEnvelope(Long userId, Long redEnvelopeId) {

        DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(String.class);
        redisScript.setScriptText(LuaScript.redLua);
        List<String> keyList = new ArrayList<>();
        /**
         * 产生的小红包key
         */
        keyList.add("{envelope}:redEnvelopeId:" + redEnvelopeId);
        /**
         * 红包领取记录key
         */
        keyList.add("{envelope}:record:" + redEnvelopeId);
        keyList.add("{envelope}" + userId);

        //keyList.add(String.valueOf(userId));
        /**
         *    -1 已经抢到红包   -2 红包已经完了   ,其余是抢到红包并返回红包余额
         */
        return stringRedisTemplate.execute(redisScript, keyList,userId+"");

lua脚本

    /**
     * -1 已经抢到红包   -2 红包被抢光  re 红包金额 ,keys[1]、keys[2]、keys[3]分别为存储小红包的key、红包领取记录key、用户id
     */
    public static String redLua = "if redis.call('hexists',KEYS[2],ARGV[1])  ~=0 then \n" +
            "  return '-1';\n" +
            " else \n" +
            "local re=redis.call('rpop',KEYS[1]);\n" +
            "if re then\n" +
            "redis.call('hset',KEYS[2],ARGV[1],1);\n" +
            "return re;\n" +
            "else\n" +
            "return '-2';\n" +
            "end\n" +
            "end";
案例二

如果value是复杂数据类型,这个时候stringRedisTemplate就不了,需要自己定制RedisTemplate

@Configuration
public class MyRedisConf {


    @Bean(name = "myRedisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(serializer);
        template.setHashValueSerializer(serializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        template.afterPropertiesSet();
        return template;
    }

}

这里还是要指定返回参数的序列化类型,不然会报错

    @Resource(name = "myRedisTemplate")
    private RedisTemplate<String,Object> redisTemplate;

    @RequestMapping("/test02")
    public void test02(){

        String script = "local receive_arg_json =  cjson.decode(ARGV[1]);\n" +
                "local v1 = receive_arg_json.v1;\n" +
                "local v2 = receive_arg_json.v2;\n" +
                "\n" +
                "redis.call('set','wxy',KEYS[1]);" +
                "return 'success';";
        DefaultRedisScript<String> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setResultType(String.class);
        defaultRedisScript.setScriptText(script);

        List<String> keyList = new ArrayList<>();
        keyList.add("{wxy}:a");
        keyList.add("{wxy}:b");

        Map<String,String> argvMap = new HashMap<>();
        argvMap.put("v1","v1");
        argvMap.put("v2","v2");

        String execute = redisTemplate.execute(defaultRedisScript,redisTemplate.getValueSerializer(), RedisSerializer.string(), keyList, argvMap);
        System.out.println("--------------------------"+execute);
    }

案例三
  @RequestMapping("/test03")
    public void test03() {


        String script = "--返回的变量\n" +
                "local result = {}\n" +
                "--获取KEY\n" +
                "--开抢时间\n" +
                "local key1 = KEYS[1]\n" +
                "--过期时间\n" +
                "local key2 = KEYS[2]\n" +
                "--红包金额分配key\n" +
                "local key3 = KEYS[3]\n" +
                "--红包领取记录key\n" +
                "local key4 = KEYS[4]\n" +
                "--红包实体信息\n" +
                "--local key5 = KEYS[5]\n" +
                "\n" +
                "--获取value ,占时是uid\n" +
                "--local value1 = ARGV[1]\n" +
                "--1.校验是否过期\n" +
                "if( redis.call('ttl',key2) == -2)\n" +
                "then\n" +
                "result[1] = '1'\n" +
                "result[2] =   cjson.encode('红包已过期')\n" +
                "return result;\n" +
                "end\n" +
                "\n" +
                "--2.校验是否触发\n" +
                "local trigger_time = redis.call('ttl',key1)\n" +
                "if(trigger_time ~= -2)\n" +
                "then\n" +
                "result[1] = '2'\n" +
                "result[2] =  trigger_time\n" +
                "return result;\n" +
                "end\n" +
                "\n" +
                "--3.校验是否已经抢过\n" +
                "if (redis.call('hexists',key4,ARGV[1])  ~=0) \n" +
                "then\n" +
                "result[1] = '3'\n" +
                "result[2] =  cjson.encode('已抢到红包')\n" +
                "return result;\n" +
                "else\n" +
                "local re = redis.call('rpop',key3)\n" +
                "if re\n" +
                "then\n" +
                "redis.call('hset',key4,ARGV[1],1)\n" +
                "result[1] = '4'\n" +
                "result[2] =  re\n" +
                "return result;\n" +
                "else\n" +
                "result[1] = '5'\n" +
                "result[2] =  cjson.encode('来慢了')\n" +
                "return result;\n" +
                "end\n" +
                "end\n" +
                "\n" +
                " \n" +
                "\n" +
                "\n" +
                "\n" +
                "\n" +
                "\n" +
                "\n" +
                "\n";



        DefaultRedisScript<List> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setResultType(List.class);
        defaultRedisScript.setScriptText(script);

        List<String> keyList = new ArrayList<>();
        keyList.add(RED_ENVELOPE_LOCK_KEY);
        keyList.add(RED_ENVELOPE_TTL_KEY);
        keyList.add(RED_ENVELOPE_AMOUNT_KEY);
        keyList.add(RED_ENVELOPE_RECORD);


        List execute = redisTemplate.execute(defaultRedisScript, keyList, 123);
        System.out.println("--------------------------" + execute);

    }

参考

https://blog.csdn.net/clfvita/article/details/73955953
https://blog.csdn.net/fsw4848438/article/details/81540495?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值