适合Ruo-Yi的请求去重方案-Redis去重

最近做了一个类似计算器的程序,要求用户可以看到之前的计算结果,这就需要把计算参数和结果分别存储起来,但是这样会遇到用户一直用同样的数据做计算,后台就会一直在存相同的数据,导致数据冗余和浪费I/O资源,这时候就要做请求去重.我这里用到的redis去重.
通常我们传到后台的大多数都是json格式,中间会有时间字段,这样会干扰我们去重,所以我们就要利用工具类把干扰去重的字段去掉,如下

//去除指定字段APi
    public String dedupParamMD5(final String reqJSON, String... excludeKeys) {
        String decreptParam = reqJSON;

        TreeMap paramTreeMap = JSON.parseObject(decreptParam, TreeMap.class);
        if (excludeKeys!=null) {
            List<String> dedupExcludeKeys = Arrays.asList(excludeKeys);  //返回去除列表
            if (!dedupExcludeKeys.isEmpty()) {
                for (String dedupExcludeKey : dedupExcludeKeys) {
                    paramTreeMap.remove(dedupExcludeKey);
                }
            }
        }
        String paramTreeMapJSON = JSON.toJSONString(paramTreeMap);
        String md5deDupParam = jdkMD5(paramTreeMapJSON);
        log.debug("md5deDupParam = {}, excludeKeys = {} {}", md5deDupParam, Arrays.deepToString(excludeKeys), paramTreeMapJSON);
        return md5deDupParam;
    }

    //MD5加密
    private static String jdkMD5(String src) {
        String res = null;
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            byte[] mdBytes = messageDigest.digest(src.getBytes());
            res = DatatypeConverter.printHexBinary(mdBytes);
        } catch (Exception e) {
            log.error("",e);
        }
        return res;
    }

我这里用了测试类去测试

 @Test
    public static void main(String[] args) {

        //两个请求一样,但是请求时间差一秒
        String req = "{\n" +
                "\"requestTime\" :\"2022102810001\",\n" +
                "\"requestValue\" :\"1000\",\n" +
                "\"requestKey\" :\"key\"\n" +
                "}";

        String req2 = "{\n" +
                "\"requestTime\" :\"2022102810002\",\n" +
                "\"requestValue\" :\"1000\",\n" +
                "\"requestKey\" :\"key\"\n" +
                "}";

        //全参数比对,所以两个参数MD5不同
        String dedupMD5 = new TestRedis().dedupParamMD5(req);
        String dedupMD52 = new TestRedis().dedupParamMD5(req2);
        System.out.println("req1MD5 = "+ dedupMD5+" , req2MD5="+dedupMD52);

        //去除时间参数比对,MD5相同
        String dedupMD53 = new TestRedis().dedupParamMD5(req,"requestTime");
        String dedupMD54 = new TestRedis().dedupParamMD5(req2,"requestTime");
        System.out.println("req1MD5 = "+ dedupMD53+" , req2MD5="+dedupMD54);

    }

接下来不如正题–redis去重
在我们在写操作之前去做判断

String dedupMD5 = new ReqDedupHelper().dedupParamMD5(req,"CreateTime");//计算请求参数摘要,其中去除里面请求时间的干扰
String KEY = "dedup:U=" + userId + "M=" + method + "P=" + dedupMD5;
long expireTime =  3600000;// 3600000毫秒过期,一小时内的重复请求会认为重复
long expireAt = System.currentTimeMillis() + expireTime;
String val = "expireAt@" + expireAt;

// 直接SETNX不支持带过期时间,所以设置+过期不是原子操作,多线程高并发情况下会出问题,后面相同请求可能会误以为需要去重,所以这里使用底层API,保证SETNX+过期时间是原子操作
Boolean firstSet = stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> connection.set(KEY.getBytes(), val.getBytes(), Expiration.milliseconds(expireTime),
        RedisStringCommands.SetOption.SET_IF_ABSENT));

这里把业务代码去除了,后面根据返回Boolean去判断要不要写入数据库.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值