即使处理了运行时异常,事务也会回滚

Transaction is rolled back even though runtime exception is handled

提问人:Satej 提问时间:9/3/2023 更新时间:9/3/2023 访问量:51

问:

正如你看到的下面的代码,我已经处理了运行时异常,并编写了一些代码来防止这个静止的事务被回滚,这让我感到惊讶。

我已经阅读了关于这个类似问题的答案,但我最终还是得到了这个问题。需要明确的解释和解决方案来解决这个问题。

[代码说明]

在下面的代码中,我试图保存一个 Event(Version 是我的 Events 表中的唯一键)类型的 obj,如果已经找到相同的版本,它会给我唯一的约束冲突异常。对于我的用例来说,这种拥有现有版本的行为是不可避免的,但是我可以增加版本并重新尝试。

[问题]

但是,我观察到的是,当它找到现有版本时,它会转到 catch 块,它确实会递增版本并尝试重试,最终它会成功。方法 m2() 最终被执行,m3() 和最后的 m1() 也是如此。

但是,我没有收到 201 响应,而是收到 500 错误,消息事务已回滚。

有什么方法可以处理这个问题?谢谢。

[代码]

@Transactional
void m1(Event event){

//DB write operation
m2(event);

//DB write operation
m3();

}

@Transactional
void m2(Event obj){

 boolean success = false;

 while(!success){

  try{

   eventRepo.save(event);
   success = true;

  } catch(UniqueConstraintViolationException e){

   event.setVersion(++event.getVersion());

   }

 }

}
 
java spring-data-jpa spring-transactions 事务管理器

评论

0赞 scrhartley 9/3/2023
如果你使用,它有帮助吗?见 baeldung.com/transaction-configuration-with-jpa-and-springdocs.spring.io/spring-framework/docs/current/javadoc-api/org/...。我不确定在重试之前是否还必须清除事件的 ID。@Transactional(noRollbackFor = { UniqueConstraintViolationException .class })
0赞 Satej 9/3/2023
但这不是理想的方法,如果其他一些代码也导致相同的异常,并且您希望在这种情况下回滚怎么办
0赞 scrhartley 9/3/2023
我不知道使用 JPA 版本控制而不是自己做:docs.oracle.com/javaee/7/api/javax/persistence/Version.html 是否会更顺畅,那么也许您可以识别 OptimisticLockException:baeldung.com/jpa-optimistic-locking
0赞 samabcde 9/3/2023
这回答了你的问题吗?UnexpectedRollbackException:事务已回滚,因为它已被标记为仅回滚
0赞 Satej 9/4/2023
@scrhartley这里的“version”不用于锁定,它是 Event 实体的属性之一。

答:

0赞 HassanUsman 9/3/2023 #1

在您的例子中,即使您捕获并重试保存操作,如果抛出异常,事务也不会提交,这就是您看到 .UniqueConstraintViolationException500 error

要处理这种情况,您可以使用一种方法。这是你如何做到的:programmatic transaction

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Autowired
private PlatformTransactionManager transactionManager;

void m1(Event event) {
    // Create a new transaction definition
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

    // Start a new transaction
    TransactionStatus status = transactionManager.getTransaction(def);

    try {
        // DB write operation
        m2(event);

        // DB write operation
        m3();

        // Commit the transaction if everything is successful
        transactionManager.commit(status);
    } catch (Exception e) {
        // Rollback the transaction if an exception occurs
        transactionManager.rollback(status);
    }
}

void m2(Event event) {
    boolean success = false;

    while (!success) {
        try {
            eventRepo.save(event);
            success = true;
        } catch (UniqueConstraintViolationException e) {
            event.setVersion(++event.getVersion());
        }
    }
}

这样,您可以在事务范围内重试,而不会影响外部事务和 。 尝试一下,如果您仍然遇到任何问题,请告诉我。handle exceptionscausing a rollback

评论

0赞 Satej 9/3/2023
transactionManager.commit(status);- > 但是@Transactional也执行提交
0赞 HassanUsman 9/3/2023
你是绝对正确的,确保正确设置了@Transactional注释的传播行为。并注意可能存在的任何数据库锁,因为这些锁可能会影响事务行为。