@Transactional 注释方法是否等待 Spring 中的成功提交?

Do @Transactional annotated methods wait for a successful commit in Spring?

在 Spring 中使用 @Transactional 注释方法时,注释方法的返回是否与底层数据库事务的成功提交同步?

(这是假设事务实际上会在返回后提交,根据所选的传播方法,情况可能并非如此。)

如果等待提交不是默认行为,是否可以通过配置或其他方式启用它?

我提出这个问题的动机是我想实现一个可靠的 "store and forward" 类型端点,它仅 returns 对客户端的响应 after调用的效果已承诺稳定存储。 @Transactional 有可能吗?

如果你没有使用@Transactional,那你会怎么处理呢?它将是类似下面的代码块

UserTransaction utx = entityManager.getTransaction(); 

try { 
    utx.begin(); 

    businessLogic();

    utx.commit(); 
} catch(Exception ex) { 
    utx.rollback(); 
    throw ex; 
}

@Transactional 实际上为你做了同样的事情。所以你可以看到它是在你的业务逻辑之后处理的。

我从这个精彩的 blog 中复制了代码。您可以查看此以了解更多详细信息。

简短的回答是否定的:该方法不等待提交。

实际发生的情况取决于两个因素:

  • 调用该方法之前是否存在事务?
  • 使用什么事务传播?

如果没有预先存在的事务,则在调用该方法之前创建一个新事务,如果它没有被标记为仅回滚,Spring 尝试在该方法之后立即提交它returns - 在这种情况下,即使该方法不等待提交,也会立即执行提交。

由于嵌套调用,在物理事务已经存在的情况下调用事务注释方法时,事情会变得更加困难

摘自 Spring 参考手册:

When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction's chance to actually commit

PROPAGATION_REQUIRES_NEW, in contrast to PROPAGATION_REQUIRED, uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction's rollback status.

PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back.

这意味着除了 PROPAGATION_REQUIRES_NEW,在包含事务结束之前不会尝试提交。

换句话说,如果您希望在事务注释方法结束后立即发生提交,则必须将传播设置为 PROPAGATION_REQUIRES_NEW:@Transactional(propagation=Propagation.REQUIRES_NEW)

我在保存交易中尝试了 PROPAGATION_REQUIRES_NEW,这对我有效。

我使用了参数isolation = Isolation.SERIALIZABLE,所以方法会在事务实际提交后结束。 (顺便说一下,我将 @Transactional 放在 Spring 引导项目中的控制器方法之上。)