玩玩Redis lua脚本(批量存值,批量加锁)

直接上代码 CV 即用,调试了一下午,好用就点个赞

import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * redis
 *
 * @Description redis
 * @Author Mr.dan
 * @Date 2023-04-05 17:54
 */
@Component
public class RedisUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
   //校验是否存在
    private static String CHECK_EXIST_TEMPLATE = "if redis.call('exists', KEYS[%s]) == 1 then return 0 end; \r\n";
    //存值
    private static String SET_TEMPLATE = "redis.call('set', KEYS[%s], ARGV[%s]); \r\n";
    //过期时间(统一)  EXPIRE 秒 PEXPIRE 毫秒 EXPIREAT 时间戳  PEXPIREAT 毫秒数的时间戳
    private static String EXPIRE_TEMPLATE = "redis.call('expire', KEYS[%s], %s); \r\n";
    //过期时间(单独)  EXPIRE 秒 PEXPIRE 毫秒 EXPIREAT 时间戳  PEXPIREAT 毫秒数的时间戳
    private static String EXPIRE_SEPARATE_TEMPLATE = "redis.call('expire', KEYS[%s], ARGV[%s]); \r\n";
    //批量删除
    private static String DELETE_TEMPLATE = "redis.call('del', KEYS[%s]); \r\n";
    //结束语
    private static String RETURN_TEMPLATE = "return 1; \r\n";

    @Override
    public void setApplicationContext(ApplicationContext ac) throws BeansException {
        //为静态属性设值
        this.applicationContext = ac;
    }

    /**
     * 执行lua脚本存入一批值 要么都成功 要么都失败
     * 适用于批量加锁的场景
     *
     * @param kvs 存一批值 不建议太多 500 以内
     * @return 成功或者失败
     */
    public static Boolean luaSetBatch(Map<String, ?> kvs, Long secondTime) {
        //这个bean 自己提前配置好 别说你不会。。。
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        StringBuilder scriptStr = new StringBuilder("");
                LuaParam luaParam = new LuaParam();
        //拼接校验脚本
        kvs.forEach((k, v) -> {
            scriptStr.append(String.format(CHECK_EXIST_TEMPLATE, luaParam.getIndex()));
            luaParam.setIndex(luaParam.getIndex() + 1);
            luaParam.getKeys().add(k);
            luaParam.getValues().add(v);
        });

        //重置下标继续拼接保存脚本
        luaParam.setIndex(1);
        kvs.forEach((k, v) -> {
            //                                           第 n 个key            第 n 个值
            scriptStr.append(String.format(SET_TEMPLATE, luaParam.getIndex(), luaParam.getIndex()));
            luaParam.setIndex(luaParam.getIndex() + 1);
        });

        //重置下标继续拼接过期脚本
        luaParam.setIndex(1);
        if (secondTime != null) {
            kvs.forEach((k, v) -> {
                //                                              第 n 个位置的key      设置为 value 的最后一个位置
                scriptStr.append(String.format(EXPIRE_TEMPLATE, luaParam.getIndex(), secondTime));
                luaParam.setIndex(luaParam.getIndex() + 1);
            });
        }

        scriptStr.append(RETURN_TEMPLATE);
        RedisScript script = RedisScript.of(scriptStr.toString(), Object.class);
        //                                          脚本串    涉及到的所有key      所有参数(必须是数组)
        Long execute = (Long) redisTemplate.execute(script, luaParam.getKeys(), luaParam.getValues().toArray());
        return execute >= 1;
    }

    /**
     * 批量删除key
     * @param keys
     */
    public static void luaDelBatch(Collection<String> keys) {
        StringBuilder scriptStr = new StringBuilder();
        LuaParam luaParam = new LuaParam();
        for (String key : keys) {
            scriptStr.append(String.format(DELETE_TEMPLATE, luaParam.getIndex()));
            luaParam.setIndex(luaParam.getIndex() + 1);
            luaParam.getKeys().add(key);
        }
        RedisScript script = RedisScript.of(scriptStr.toString(), Object.class);
        redisTemplate().execute(script, luaParam.getKeys());
    }

    @Data
    static class LuaParam {
        /**
         * 当前循环到的下标
         */
        private int index = 1;
        /**
         * 所有的key
         */
        private List<String> keys = new ArrayList<>();
        /**
         * 所有的值
         */
        private List values = new ArrayList<>();
        /**
         * 所有Key的过期时间
         */
        private List<Long> expireTimes = Lists.newArrayList();
    }
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值