栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

知识积累:解决前端重复请求导致数据出现重复问题,幂等性实现基于Redis,多端操作重复数据幂等问题,附代码

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

知识积累:解决前端重复请求导致数据出现重复问题,幂等性实现基于Redis,多端操作重复数据幂等问题,附代码

场景:

项目当中经常出现相同时间点的数据存入两条一模一样的数据,通常是由于页面或客户端网络延迟导致的重复提交导致的。这种情况,如果没有唯一业务字段的索引处理,就会导致重复数据出现在我们的MySQL数据表中。这时候只能手动删除掉重复的数据,以免影响业务正常使用。
下面是针对这种问题的后端解决方案。 方案不是最好的,但是能有效避免重复数据的产生。

传送门:幂等性问题的思考和总结,防重、幂等,常用解决方案,解决方式

实现方案:

根据请求信息进行md5计算,保存到Redis,有效期1小时;
下次请求再进来判断Redis是否存在?如果已存在,提示重复请求。

具体代码实现: 1、声明注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface RepeatRequestInterceptor {

}
2、使用注解
@RepeatRequestIntercept
@ApiOperation(value = "申请")
@PostMapping("/applyRefund")
public RefundApplyVO applyRefund(@Validated @RequestBody RefundApplyDTO refundApplyDTO) {
  do something...
  return new RefundApplyVO(refundOrder.getId());
}
3、处理注解的统一切面类
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;


@Aspect
@Component
@Slf4j
public class RepeatRequestAspect {

    private static final String REPEAT_REQUEST_REDIS_KEY = "repeat_request:";

    
    private static final Integer REPEAT_REQUEST_TIMEOUT = 3600;

    @Resource
    private RedisClient redisClient;

    @Around("@annotation(com.xxxx.web.RepeatRequestInterceptor)")
    public Object before(ProceedingJoinPoint joinPoint) throws Throwable {
        Long userId = UserContext.getUserId();
        Object[] args = joinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        String requestInfo = joinPoint.getTarget() + method.getName() + userId + userId + JSONObject.toJSONString(args);

        String md5 = Md5Utils.getMD5(requestInfo.getBytes());
        String lockKey = REPEAT_REQUEST_REDIS_KEY.concat(md5);
        Boolean lockFlag = false;
        try {
        	// Redis缓存1小时基于请求内容计算的md5值
            lockFlag = redisClient.setNx(lockKey, md5, REPEAT_REQUEST_TIMEOUT);
            if (lockFlag) {
                return joinPoint.proceed();
            } else {
                throw new BizException(BaseResultCodeEnum.REPETITIVE_OPERATION);
            }
        } finally {
            if (lockFlag) {
                redisClient.delete(lockKey);
            }
        }
    }
}

下面是基于这种问题的前后端解决方案
思路大概是:

  1. 后端统一生成一个唯一token值,
  2. 前端在数据提交之前获取这个token值,数据提交的时候统一将这个token通过header传给后端,
  3. 后端先判断token是否存在Redis中,存在则提示重复请求,不存在就将token保存到Redis中(有效期2小时可调整)。

代码明细稍候提供

-------------欢迎各位留言交流,如有不正确的地方,请予以指正。【Q:981233589】

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/943823.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号