Redis结合Lua脚本的简单使用

我们就拿购物车举例子

现在有5个东西免费送,我们只能选择1个

例如 可乐 美年达 香蕉 苹果 薯片

我们选择后就放进redis里面

然后我们不能选重复,只能选不同

Lua脚本

我们redis使用lua脚本的时候,会传两个参数进去

一个是List<String>类型,一个是Object【】类型

KEYS【】对应的是List类型 ARGV【】对应的是Object【】类型

复制代码
-- 购物车的东西是一样的,不需要修改
if (redis.call('get', KEYS[1]) == ARGV[1]) then
    return 0
elseif (redis.call('get', KEYS[1]) ~= '') then
    -- 购物车的东西是不一样的,需要修改
    -- 先删除
    redis.call('del', KEYS[1])
    --然后重新设置购物车
    redis.call('set', KEYS[1], ARGV[1])
elseif (redis.call('get', KEYS[1]) == '') then
    --购物车为空,直接添加
    redis.call('set', KEYS[1], ARGV[1])
end

return 0

静态代码块读取Lua脚本,减少IO流

案例

我们首先往购物车里面添加苹果

然后使用execute()方法调用Lua脚本

然后传参数进去

此时我们的lua脚本用的是ARGV【1】

对应的是香蕉

我们使用后,发现redis里面变成香蕉了

如果我们像变成其他,那么在lua脚本中的ARGV【】参数里面改数字就好了

测试类代码

复制代码
package com.example.admin;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
public class RedisTest {

    //为了防止每次加载都读取lua文件产生大量IO流,所以我们弄成静态代码块直接就读取好
private static final DefaultRedisScript UNLOCK_SCKIP;
static {
    UNLOCK_SCKIP=new DefaultRedisScript<>();
    UNLOCK_SCKIP.setLocation(new ClassPathResource("unlock.lua"));
}


    @Autowired
    StringRedisTemplate stringRedisTemplate;

@Test
void add(){

    stringRedisTemplate.opsForValue().set("购物车", "苹果");

}


    @Test
    void change(){

    //苹果,香蕉,可乐,美年达,薯片

        List<String> list=new ArrayList<>();
        list.add("购物车");
//调用LUA脚本
        stringRedisTemplate.execute(
                UNLOCK_SCKIP,
                  list,
                "香蕉","苹果","可乐","美年达","薯片"
        );

    }




}

Lua脚本实现限流操作

这个是lua脚本

复制代码
-- 设置用户访问频率限制的参数
local username = KEYS[1]
local timeWindow = tonumber(ARGV[1]) -- 时间窗口,单位:秒

-- 构造 Redis 中存储用户访问次数的键名
local accessKey = "short-link:user-flow-risk-control:" .. username

-- 原子递增访问次数,并获取递增后的值
local currentAccessCount = redis.call("INCR", accessKey)

-- 设置键的过期时间
redis.call("EXPIRE", accessKey, timeWindow)


--返回当前次数
return currentAccessCount

因为我们要使用到lua脚本的返回值

所以我们要setResultType()来设置我们的返回值是String类型

这样子才能成功拿到返回值,亲测如果不设置,那么我们拿到的返回值就是为null

测试

测试类代码

复制代码
package com.example.admin;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
public class RedisTest {

    //为了防止每次加载都读取lua文件产生大量IO流,所以我们弄成静态代码块直接就读取好
private static final DefaultRedisScript UNLOCK_SCKIP;
    private static final DefaultRedisScript INCREMENT;
static {
    UNLOCK_SCKIP=new DefaultRedisScript<>();
    UNLOCK_SCKIP.setLocation(new ClassPathResource("unlock.lua"));

    INCREMENT=new DefaultRedisScript<>();
    INCREMENT.setLocation(new ClassPathResource("Increment.lua"));
    //要加上这个,因为lua脚本的返回值是String类型
    INCREMENT.setResultType(String.class);

}






    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    void increment(){

        List<String> list =new ArrayList<>();
        list.add("KIRA");


        for (int i = 0; i < 15; i++) {
             Object result = stringRedisTemplate.execute(INCREMENT,
                    list,
                    "10");


            System.out.println(result);

            if((Long)result>10L)
                System.out.println("超出阈值,暂停一会然后重试");
        }



    }

@Test
void add(){

    stringRedisTemplate.opsForValue().set("购物车", "苹果");

}


    @Test
    void change(){

    //苹果,香蕉,可乐,美年达,薯片

        List<String> list=new ArrayList<>();
        list.add("购物车");
//调用LUA脚本
        stringRedisTemplate.execute(
                UNLOCK_SCKIP,
                  list,
                "香蕉","苹果","可乐","美年达","薯片"
        );

    }




}
相关推荐
2301_813599552 小时前
Go语言怎么做秒杀系统_Go语言秒杀系统实战教程【实用】
jvm·数据库·python
NCIN EXPE6 小时前
redis 使用
数据库·redis·缓存
MongoDB 数据平台6 小时前
为编码代理引入 MongoDB 代理技能和插件
数据库·mongodb
极客on之路6 小时前
mysql explain type 各个字段解释
数据库·mysql
代码雕刻家6 小时前
MySQL与SQL Server的基本指令
数据库·mysql·sqlserver
lThE ANDE6 小时前
开启mysql的binlog日志
数据库·mysql
hERS EOUS6 小时前
nginx 代理 redis
运维·redis·nginx
yejqvow127 小时前
CSS如何控制placeholder文字的颜色_使用--placeholder伪元素
jvm·数据库·python
oLLI PILO7 小时前
nacos2.3.0 接入pgsql或其他数据库
数据库
m0_743623927 小时前
HTML怎么创建多语言切换器_HTML语言选择下拉结构【指南】
jvm·数据库·python