Antirreproducción operación de registro de registro y presentar

debido

Enviar una prueba de disparos parecían decir que debido a la tarjeta de red, lo que lleva a añadir un punto N veces los datos, los resultados en una lista se ha añadido a la N.

análisis

Ver código, antes de introducir los datos, hay una consulta de si el contenido del campo en base a datos ya existen, existe para actualizar o agregar. Todavía esto sucede, muchos casos pueden conducir a:
1, cuando solicitudes simultáneas vienen en, consultas simultáneas no están presentes, el inserto concurrente final, resultando en datos sucios;
2, aplicaciones distribuidas, en la ejecución de la operación de inserción correspondiente, sin base de datos de tabla de bloqueo operado.
El segundo punto es el proceso más complejo, a continuación, de nuevo, el primer punto 1 proceso, la operación del mismo usuario (la misma petición) devuelve el resultado de la operación debe esperar antes de permitir que una segunda solicitud, evitando así petición operación complicada.

demanda

1, después de enviar la solicitud hasta que la parte delantera, no se devuelve ninguna respuesta, el botón de apagado inhabilitar la operación
2, el extremo posterior de la operación de grabación del registro de usuario, agregar, modificar y operaciones de borrado presentó antirreproducción

diseño

Búsqueda de información en Internet mediante el registro del registro de la operación y anti volver a presentar la sección de AOP para el procesamiento de uso general, y la cerradura como la identificación por Redis

proceso

1. Definir un comentario

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAndNoRepeatSubmit {

    String value() default "";

    int lockTime() default 10;
}

2, un método de sección creciente

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Resource
    private AsyncTaskService asyncService;

    @Pointcut("@annotation(logAndNoRepeatSubmit)")
    public void pointcut(LogAndNoRepeatSubmit logAndNoRepeatSubmit) {
    }

    @Around(value = "pointcut(logAndNoRepeatSubmit)")
    public Object around(ProceedingJoinPoint point, LogAndNoRepeatSubmit logAndNoRepeatSubmit) throws Throwable {
        long beginTime = System.currentTimeMillis();
        int lockSeconds = logAndNoRepeatSubmit.lockTime();
        String key = LogAspectUtil.getKeyFromRequest();
        String clientId = UUID.randomUUID().toString();
        boolean isSuccess=false;
        //在并发情况下,redis请求会有大概10ms的请求时长,因此加锁,避免redis还没有执行加锁,其他请求已经进来而导致与预期不一致的情况
        synchronized (this) {
            isSuccess = RedisUtil.tryLock(CacheConst.IDEMPOTENCE + key, clientId, lockSeconds);
        }
        if (isSuccess) {
            Object result = null;
            try {
                result = point.proceed();
            } catch (Throwable e) {
                log.error("不重复提交日志", e);
                throw e;
            } finally {
                RedisUtil.del(CacheConst.IDEMPOTENCE + key);
            }
            long time = System.currentTimeMillis() - beginTime;
            Long uid = UserCacheUtil.getUserInfo().getId();
            String userName = UserCacheUtil.getUserInfo().getName();
            String ip = WebUtil.getIP();
            //记录操作日志
            OperationLogDTO dto = LogAspectUtil.handleLog(point, time, result, uid, userName, "COM-PC", ip);
            saveLog(dto);
            return result;
        } else {
            return R.fail("重复请求,请稍后再试");
        }
    }

    private void saveLog(OperationLogDTO dto) {
        // 保存系统日志,异步方法保存,或者放到MQ去执行
       asyncService.saveLog(dto);
    }
}

3, diseñados para funcionar contenido de registro:

CREATE TABLE `operation_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uid` bigint(20) DEFAULT NULL,
  `user_name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
  `operation` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
  `response_time` bigint(5) DEFAULT NULL,
  `method` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
  `params` text CHARACTER SET utf8mb4,
  `ip` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
  `ctime` datetime DEFAULT NULL,
  `status` bit(1) DEFAULT NULL,
  `response_code` int(4) DEFAULT NULL,
  `response_msg` varchar(1000) CHARACTER SET utf8mb4 DEFAULT NULL,
  `request_side` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2690 DEFAULT CHARSET=utf-8;

4, la prueba
usando jmeter hacer concurrentes 5 peticiones de prueba
se puede ver que cuando la primera solicitud no se ha completado, todas las demás solicitudes se les niega

resumen

Anti-pesada presentar evitar la aparición de datos sucios, en cierta medida, la necesidad posterior para mejorar el procesamiento simultáneo de aplicaciones distribuidas.

Publicado cuatro artículos originales · ganado elogios 0 · Vistas 36

Supongo que te gusta

Origin blog.csdn.net/m0_37453314/article/details/105409513
Recomendado
Clasificación