有一个实体:
@Entity
class A {
...
@Version
int version;
}
A
以乐观方式实现的实例更新:
@Transactional(rollbackFor = {StaleStateException.class})
@Retryable(value = {StaleStateException.class})
public void updateA() {
A a = findA();
B b = new B();
// Update "a" somehow
a.update();
// "b" is saved on each retry!
save(b);
}
正如评论中所述,当 StaleStateException
发生时,事务似乎没有回滚,因此每次重试时都会保存 B
实例。
是否可以在重试时回滚事务?
所需的行为是 b
仅在成功更新 a
时保存。
最佳答案
我认为这可能与@Retryable
配置有关。
正如文档所说 https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statelessRetry无状态可重试只不过是一个不断调用相同方法直到成功的循环。
问题是每次它失败时调用的第一个拦截器是不会重新抛出异常的可重试,所以它永远不会到达 @Transactional
那个。
因此,每次重试都将遵循默认事务传播,这将在上下文中使用 new B()
重用相同的已打开事务。
你可以通过调试来检查我是否在正确的引导上:如果你进入第二次重试并发现 A
在更新 block 之前已经更新那么我应该是正确的。
您可以通过两种方式修复:
要么划分两个 block (先用嵌套事务重试)
@Retryable(value = {StaleStateException.class})
public void retryableUpdate() {
updateA();
}
@Transactional(rollbackFor = {StaleStateException.class})
public void updateA() {
A a = findA();
B b = new B();
// Update "a" somehow
a.update();
// "b" is saved on each retry!
save(b);
}
以便事务先回滚。
或者您可以按照文档使用有状态重试 https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statefulRetry
关于java - Spring 数据 : rollback transaction on retry,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47743557/