Java 乐观锁定的重试机制(spring数据+;JPA)
我们决定在web应用程序中使用乐观锁定,以提高并发性,而不使用悲观锁定 我们现在正在寻找重试解决方案 我们希望对当前代码库的影响尽可能小 我们在web上看到的解决方案之一是使用带有注释的重试拦截器将方法标记为可重试 问题是,我们希望对具有@Transactional注释的方法进行注释,但由于某些原因,拦截器无法重试这些方法。(拦截器会完美地重试非事务性方法。) 因此: 1) 有没有对代码影响最小的重试替代方案 2) 是否有该解决方案的文档\教程 3) 甚至可以重试@Transactional注释方法吗Java 乐观锁定的重试机制(spring数据+;JPA),java,spring,hibernate,jpa,optimistic-locking,Java,Spring,Hibernate,Jpa,Optimistic Locking,我们决定在web应用程序中使用乐观锁定,以提高并发性,而不使用悲观锁定 我们现在正在寻找重试解决方案 我们希望对当前代码库的影响尽可能小 我们在web上看到的解决方案之一是使用带有注释的重试拦截器将方法标记为可重试 问题是,我们希望对具有@Transactional注释的方法进行注释,但由于某些原因,拦截器无法重试这些方法。(拦截器会完美地重试非事务性方法。) 因此: 1) 有没有对代码影响最小的重试替代方案 2) 是否有该解决方案的文档\教程 3) 甚至可以重试@Transactional注释
干杯 实现这一点有两种方法,如下所示 或 希望这对你有帮助 公元3年。 当版本号或时间戳检查失败(发生乐观锁定)时,可以使用重试事务处理的方法 配置 用法
@Retryable(StaleStateException.class)
@交易的
公共void doSomethingWithFoo(长fooId){
//更改前请再次阅读您的实体!
Foo-Foo=foosrepository.findOne(fooId);
foo.setStatus(已拒绝)/重试无法工作的原因是@Transactional priority高于@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;
}
}
您的服务类方法应该添加注释@IstryReach和@Transactional
@IsTryAgain
@Transactional(rollbackFor = Exception.class)
public Product buyProduct(Product product) {
// your business logic
}
Ashish,我们已经尝试了第二种解决方案,当您在事务性方法上使用它时,它显然不起作用,您知道为什么吗?我完全按照编写的内容进行了操作,然后我用@RetryConcurrentOperation(exception=HibernateOptimisticLockingFailureException.class,retries=12)注释了一个服务方法现在,由于该方法是用@Transactional注释的,因此它不起作用,如果我对非事务性方法进行注释,它会在非事务性方法上产生一个常规的乐观锁异常——它起作用。“SQLException:语句已关闭。”退休时发生。@xiemeilong我和你在Hibernate 5.0.x上犯了同样的错误。它在5.2.14.Final中消失了。我花了将近一天的时间才弄清楚。:(@Jean Françoisbauchef非常感谢你,我稍后再试。
@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(rollbackFor = Exception.class)
public Product buyProduct(Product product) {
// your business logic
}