• 防止重复请求


    问题描述 
    前段时间遇到个问题,自己内部系统调用出现重复请求导致数据混乱。 
    发生条件:接受到一个请求,该请求没有执行完成又接受到相同请求,导致数据错误(如果是前一个请求执行完成,马上又接受相同请求不会有问题) 
    问题分析:是由于数据库的脏读导致 
    问题解决思路 
    1.加一把大大的锁 (是最简单的实现方式,但是性能堪忧,而且会阻塞请求) 
    2.实现请求拦截 (可以共用,但是怎么去实现却是一个问题,怎么用一个优雅的方式实现,并且方便复用) 
    3.修改实现 (会对原有代码做改动,存在风险,最主要的是不能共用) 
    最终实现方式第2中 
    通过注解+spring AOP 的方式实现 
    使用 
    通过在任意方法上添加注解NotDuplicate 
    类1:
    import static java.lang.annotation.ElementType.METHOD;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface NotDuplicate {
    }
    import java.lang.reflect.Method;
    import java.util.Set;
    import java.util.concurrent.ConcurrentSkipListSet;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    
    
    @Aspect
    @Component
    public class NotDuplicateAop {
    
        private static final Set<String> KEY =  new ConcurrentSkipListSet<>();
    
        @Pointcut("@annotation(com.hhly.skeleton.base.filter.NotDuplicate)")
        public void duplicate() {
        }
    
        /**
         * 对方法拦截后进行参数验证
         * @param pjp
         * @return
         * @throws Throwable
         */
        @Around("duplicate()")
        public Object duplicate(ProceedingJoinPoint pjp) throws Throwable {
            MethodSignature msig = (MethodSignature) pjp.getSignature();
            Method currentMethod = pjp.getTarget().getClass().getMethod(msig.getName(), msig.getParameterTypes());
            //拼接签名
            StringBuilder sb = new StringBuilder(currentMethod.toString());
            Object[] args = pjp.getArgs();
            for (Object object : args) {
                if(object != null){
                    sb.append(object.getClass().toString());
                    sb.append(object.toString());
                }
            }
            String sign = sb.toString();
            boolean success = KEY.add(sign);
            if(!success){
                throw new ServiceRuntimeException("该方法正在执行,不能重复请求");
            }
            try {
                return pjp.proceed();
            } finally {
                KEY.remove(sign);
            }
    
        }
    }
  • 相关阅读:
    解决PKIX:unable to find valid certification path to requested target 的问题
    Linux 上的常用文件传输方式介绍与比较
    用VNC远程图形化连接Linux桌面的配置方法
    红帽中出现”This system is not registered with RHN”的解决方案
    linux安装时出现your cpu does not support long mode的解决方法
    CentOS SSH配置
    es6扩展运算符及rest运算符总结
    es6解构赋值总结
    tortoisegit安装、clon、推送
    es6环境搭建
  • 原文地址:https://www.cnblogs.com/chengyangyang/p/10845573.html
Copyright © 2020-2023  润新知