Spring @Transactional 在每个服务方法结束时提交

Spring @Transactional commits at the end of each service method

我在 Vaadin Spring 项目中配置了一个常用的声明式事务管理。我在我的 root-context.xml 中添加了 <tx:annotation-driven transaction-manager="transactionManager" /> 并且在 pom.xml 中添加了所有其他必需的 Maven 依赖项。 我的服务方法用 @Transactional 注释并带有默认传播。

我想从 UI 端的一个方法调用两个服务方法,希望这两个服务方法参与单个事务,因为默认传播是 PROPAGATION_REQUIRED。但是这两种方法是独立地提交给数据库的。这意味着如果第二种方法失败,第一种方法无论如何都会提交给数据库。我没有使用 try{}catch{{ 块,所以任何 RuntimeException 都会冒出来。

已附加 spring 日志。删除了一些行以减少行数

[qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/getTransaction Creating new transaction with name [...UserServiceImpl.turnOnPwdResetFlag]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/doBegin Switching JDBC Connection [com.jolbox.bonecp.ConnectionHandle@42398a05] to manual commit [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/handleExistingTransaction Participating in existing transaction [qtp187048467-48] DEBUG o.s.jdbc.core.JdbcTemplate/doInStatement SQL update affected 1 rows [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/processCommit Initiating transaction commit [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/doCommit Committing JDBC transaction on Connection [com.jolbox.bonecp.ConnectionHandle@42398a05] [qtp187048467-48] DEBUG o.s.jdbc.datasource.DataSourceUtils/doReleaseConnection Returning JDBC Connection to DataSource ` ` [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/getTransaction Creating new transaction with name [...UserServiceImpl.turnOffPwdResetFlag]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT;  [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/handleExistingTransaction Participating in existing transaction [qtp187048467-48] DEBUG o.s.jdbc.datasource.DataSourceUtils/doReleaseConnection Returning JDBC Connection to DataSource 

如果你想为两个方法调用都使用一个事务,你必须确保调用这两个方法的方法也有事务注释,就像这个例子:

@Transactional
public void callingMethod() {
    method1();
    method2();
}

@Transactional
public void method1() {
}

@Transactional
public void method2() {
}

Spring transaction internals, Open session in view filter 的帮助下,我想出了一个解决方案。

根据第一个 link,在 Spring MVC 上下文中,事务在控制器上下文中开始,然后服务层中的 @Transactional 方法参与、创建或创建另一个事务在已经存在的交易之上进行适当的交易。但是,如果 UI 层不是 Spring MVC,则不会发生这种情况。

如此 Spring transaction image 所示,事务顾问负责决定是提交事务还是标记回滚。因此,如果我们只是让服务方法代理在事先不存在的地方创建一个事务,那么在该代理方法结束时,顾问会决定提交该事务。为了克服这个问题,我们必须在两个服务方法调用之前创建一个事务,这样这两个方法将加入事务而不是由它们自己提交。

Hibernate context the Spring MVC supports OpenSessionInView, which creates a transaction per request. What I have done is create a similar servlet filter to create a transaction at the beginning of a request and commits at the end of filter chain. This works perfectly in Vaadin, Spring and JDBC environment. If you are so concerned that a Spring transaction and hence a database connection is acquired on every HTTP request, try using a LazyConnectionDataSourceProxy

在此处查看解决方案:I want to... Use JDBC, Spring transactions and @Transactional