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
我在 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