在我以前的文章中,我谈到了对MongoDB批处理程序采用乐观锁定的好处。 如我之前所写,乐观锁异常是可恢复的异常,只要我们获取最新的Entity,我们就会对其进行更新并保存。
因为我们使用的是MongoDB,所以我们不必担心本地或XA事务。 在以后的文章中,我将演示如何使用JPA构建相同的机制。
Spring框架提供了很好的AOP支持,因此可以轻松实现自动重试机制,这就是我的方法。
我们首先定义一个Retry注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retry {
Class<? extends Exception>[] on();
int times() default 1;
}
我们注释了我们的业务逻辑方法,例如
@Retry(times = 10, on = org.springframework.dao.OptimisticLockingFailureException.class)
public Product updateName(Long id, String name) {
Product product = productRepository.findOne(id);
product.setName(name);
LOGGER.info("Updating product {} name to {}", product, name);
return productRepository.save(product);
}
然后,我们只需要AOP方面来拦截业务逻辑调用,并在乐观锁定检测的情况下重试。
@Aspect
public class OptimisticConcurrencyControlAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(OptimisticConcurrencyControlAspect.class);
@Around("@annotation(vladmihalcea.concurrent.Retry)")
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
Retry retryAnnotation = getRetryAnnotation(pjp);
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
}
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
int times = retryAnnotation.times();
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
LOGGER.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn);
}
private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
try {
return proceed(pjp);
} catch (Throwable throwable) {
if(isRetryThrowable(throwable, retryOn) && times-- > 0) {
LOGGER.info("Optimistic locking detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn);
}
throw throwable;
}
}
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
for(Throwable cause : causes) {
for(Class<? extends Throwable> retryThrowable : retryOn) {
if(retryThrowable.isAssignableFrom(cause.getClass())) {
return true;
}
}
}
return false;
}
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
if(retryAnnotation != null) {
return retryAnnotation;
}
Class[] argClasses = new Class[pjp.getArgs().length];
for (int i = 0; i < pjp.getArgs().length; i++) {
argClasses[i] = pjp.getArgs()[i].getClass();
}
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
return AnnotationUtils.findAnnotation(method, Retry.class);
}
}
测试开始了10个竞标以竞争产品的保存,这就是测试日志。
Line 492: INFO [Thread-9]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 495: INFO [Thread-3]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 504: INFO [Thread-8]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 505: INFO [Thread-11]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 507: INFO [Thread-10]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 513: INFO [Thread-5]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 523: INFO [Thread-4]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 9 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 529: INFO [Thread-3]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 8 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 586: INFO [Thread-10]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 8 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 682: INFO [Thread-5]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 8 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 683: INFO [Thread-3]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 7 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 686: INFO [Thread-8]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 8 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 702: INFO [Thread-3]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 6 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 752: INFO [Thread-5]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 7 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 756: INFO [Thread-8]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 7 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
Line 859: INFO [Thread-5]: v.c.a.OptimisticConcurrencyControlAspect - Optimistic locking detected, 6 remaining retries on [class org.springframework.dao.OptimisticLockingFailureException]
- 代码可在GitHub上获得 。
翻译自: https://www.javacodegeeks.com/2013/11/optimistic-locking-retry-with-mongodb.html
本文介绍了如何在MongoDB中利用乐观锁定进行重试操作,通过Spring AOP支持创建自动重试机制。文章展示了如何定义Retry注解,并将其应用于业务逻辑方法,当遇到乐观锁定异常时进行重试。文中还提到了一个测试场景,10个并发竞标尝试保存产品,并提供了GitHub上的代码示例。

3792

被折叠的 条评论
为什么被折叠?



