背景
后端业务中,不能相信任何一个用户,永远不知道这个用户能做出来什么事情,他可能一个表单一秒点了好多次,在程序懵逼中就插进数据库了!
措施
这里采用redis
锁的方式来实现
核心用 锁的名称+userid
+方法名 做redis
的key
code
这里采用AOP
的方式来实现,实现耦合性降低到最小,零侵入,这就是java语言的妙处!
完整代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventRepeat {
/**
* 锁的名称,可不填
*
* @return
*/
String key() default "";
/**
* 锁住的秒数
*
* @return
*/
int second() default 1;
}
@Aspect
@Component
@Slf4j
public class PreventRepeatAspect {
@Resource
private RedisUtil redisUtil;
@Pointcut("@annotation(com.xx.xx.api.annotation.PreventRepeat)")
public void commitPointCut() {
}
@Around("commitPointCut()")
public Object around(JoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
Class<?> clazz = joinPoint.getTarget().getClass();
//获取方法签名(通过此签名获取目标方法信息)
MethodSignature ms=(MethodSignature)joinPoint.getSignature();
Method method = clazz.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
PreventRepeat annotation = method.getAnnotation(PreventRepeat.class);
if (ObjectUtils.isNotEmpty(annotation)) {
String userId = xxxx;
String lockKey = StringUtils.isNotEmpty(annotation.key()) ? annotation.key() : userId + ":" + methodName;
if (!redisUtil.lock(lockKey, lockKey, annotation.second())) {
return Result.errorResult("请不要重复提交");
}
}
return ((ProceedingJoinPoint) joinPoint).proceed();
}
}