繁体   English   中英

乐观锁重试机制(spring data + JPA)

[英]Retry mechanism for optimistic locking (spring data + JPA)

我们决定在我们的 Web 应用程序中使用乐观锁定以增加并发性,而不使用悲观锁定。

我们现在正在寻找重试解决方案。

我们希望对我们当前的代码库产生尽可能小的影响。

我们在网上看到的解决方案之一是使用带有注释的重试拦截器将方法标记为可重试。

问题是我们想注释具有 @Transactional 注释的方法,但由于某种原因拦截器无法重试它们。 (拦截器完美地重试非事务方法。)

所以:

1) 是否有任何重试替代方案对我们的代码影响最小?

2)该解决方案是否有任何文档\\教程?

3) 甚至可以重试@Transactional 注释方法吗?

干杯!

广告 3.

当版本号或时间戳检查失败(发生乐观锁)时,您可以使用Spring Retry 重事务方法。

配置

@Configuration
@EnableRetry
public class RetryConfig {

}

用法

@Retryable(StaleStateException.class)
@Transactional
public void doSomethingWithFoo(Long fooId){
    // read your entity again before changes!
    Foo foo = fooRepository.findOne(fooId);

    foo.setStatus(REJECTED)  // <- sample foo modification

} // commit on method end

使用@Transactional (propagation = Propagation.REQUIRES_NEW)仅重试来自注释方法的代码。

您有两种方法可以实现这一点,如下所示

从休眠乐观锁定异常中恢复

或者

使用 Spring AOP 重试失败的幂等并发操作

希望能帮到你..!

您重试无法工作的原因是@Transactional 优先级高于@Aspect。

您应该通过在 TryAgainAspect 类中实现 Ordered来提高 @Aspect 的优先级

拦截器类:

@Aspect
@Component
public class TryAgainAspect implements Ordered {

private int maxRetries;
private int order = 1;

public void setMaxRetries(int maxRetries) {
    this.maxRetries = maxRetries;
}

public int getOrder() {
    return this.order;
}

@Pointcut("@annotation(IsTryAgain)")
public void retryOnOptFailure() {
}

@Around("retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    MethodSignature msig = (MethodSignature) pjp.getSignature();
    Object target = pjp.getTarget();
    Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    IsTryAgain annotation = currentMethod.getAnnotation(IsTryAgain.class);
    this.setMaxRetries(annotation.tryTimes());

    int numAttempts = 0;
    do {
        numAttempts++;
        try {
            return pjp.proceed();
        } catch (ObjectOptimisticLockingFailureException | StaleObjectStateException exception) {
            exception.printStackTrace();
            if (numAttempts > maxRetries) {
                throw new NoMoreTryException("System error, all retry failed");
            } else {
                System.out.println("0 === retry ===" + numAttempts + "times");
            }
        }
    } while (numAttempts <= this.maxRetries);

    return null;
}

}

再试一次:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsTryAgain {
    int tryTimes() default 5;
}

您的服务类方法应添加注释 @IsTryAgain 和 @Transactional

@IsTryAgain
@Transactional(rollbackFor = Exception.class)
public Product buyProduct(Product product) {
// your business logic 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM