java - Spring 数据 : rollback transaction on retry

标签 java hibernate spring-boot spring-data optimistic-locking

有一个实体:

@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/

相关文章:

java - 尝试使用枚举作为与 thymeleaf 一起使用的输入

angular - 如何从 HAL 响应中获取我的资源数据?

java - 如何设计一个 View 来模拟 Web 服务调用时的自动转换?

java - EC2 上跨 jgroups channel 丢失数据包的问题

java - Hibernate - 自定义 ID 生成

java - 如何处理libGDX的Box2D ContactListener中的空指针异常?

java - Hibernate 5 Infinispan :java. lang.NoSuchMethodError : org. jboss.logging.Logger.debugf(Ljava/lang/String;I)V

java - 批量插入导致失败

java sendkeys 错误键应该是一个字符串

java - 为什么修饰符在似乎什么都不做的情况下允许用于包?