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

    }




}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值