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,
                "香蕉","苹果","可乐","美年达","薯片"
        );

    }




}
相关推荐
盒马coding2 分钟前
PostgreSQL 空闲空间映射(FSM)深度解读
数据库·postgresql
vistaup41 分钟前
Android ContentProvier
android·数据库
Pluchon1 小时前
硅基计划5.0 MySQL 陆 视图&JDBC编程&用户权限控制
数据库·mysql·1024程序员节
摇滚侠1 小时前
Spring Boot3零基础教程,自定义 starter,把项目封装成依赖给别人使用,笔记65
数据库·spring boot·笔记
不剪发的Tony老师1 小时前
SQLiteSpy:一款轻量级的SQLite管理工具
数据库·sqlite
一 乐1 小时前
车辆管理|校园车辆信息|基于SprinBoot+vue的校园车辆管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·车辆管理
得物技术1 小时前
告别数据无序:得物数据研发与管理平台的破局之路
大数据·数据库·数据分析
EndingCoder2 小时前
Node.js 数据查询优化技巧
服务器·javascript·数据库·node.js·数据查询优化
TDengine (老段)2 小时前
TDengine 数学函数 SIGN 用户手册
大数据·数据库·sql·时序数据库·iot·tdengine·涛思数据
RestCloud3 小时前
Kingbase 与 ETL:如何实现金融级数据库的安全数据同步
数据库·数据安全·etl·数据处理·数据传输·数据同步·kingbase