如果有错误的地方,大家可以指正出来:
使用:
@TransactionalWithRetries
方法 :{
dto = select 。。
update (dto)
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TransactionalWithRetries {
int maxTimes() default 3;
}
@Aspect
@Component
public class RetryOptLockAop {
private final static Logger log = LoggerFactory.getLogger(RetryOptLockAop.class);
@Autowired
TransactionTemplate transactionTemplate;
@Pointcut("@annotation(TransactionalWithRetries)")
public void retryOnOptFailure() {
}
@Around("retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
// 参数序列化反序列化,保证不会改变(参数为对象,可能会被方法修改)
byte[] args = SerializationUtils.serialize(pjp.getArgs());
TransactionalWithRetries annotation = signature.getMethod().getAnnotation(TransactionalWithRetries.class);
// 获取注解参数
int maxTimes = annotation.maxTimes();
// 没有并发。这样写只是因为lambda表达式里不能直接赋值
AtomicInteger count = new AtomicInteger(0);
AtomicReference<Object> result = new AtomicReference<>();
while (count.get() < maxTimes) {
try {
// 事务。如果execut里不抛异常,commit。如果抛异常,会传递出来
transactionTemplate.execute(status -> {
Throwable throwable = null;
try {
result.set(pjp.proceed((Object[]) SerializationUtils.deserialize(args)));
} catch (Throwable t) {
throwable = t;
}
if (throwable != null || !isSuccess(result.get())) {
if (throwable == null) {
throw new RuntimeException("TransactionalWithRetries OptLock:" + signature.getMethod().getName());
} else {
throw new RuntimeException(throwable);
}
} else {
// 不再进行重试
count.set(maxTimes);
}
return result.get();
});
} catch (Throwable t) {
count.incrementAndGet();
log.error("TransactionalWithRetries method:{} args:{} result:{}",
signature.getMethod().getName(), SerializationUtils.deserialize(args), result.get(), t);
}
}
return result.get();
}
// 方法返回结果为false,或者小于0的数字,也进行重试
boolean isSuccess(Object obj) {
if (obj != null) {
if (obj instanceof Boolean) {
return (boolean) obj;
}
if (obj instanceof Number) {
if ((int) obj <= 0) {
return false;
}
}
}
return true;
}
}