简体   繁体   中英

Spring @Transactional commits at the end of each service method

I have configured a usual declarative transaction management in a Vaadin, Spring project. I have added <tx:annotation-driven transaction-manager="transactionManager" /> in my root-context.xml and all other required maven dependencies in the pom. My Service methods are annotated with @Transactional with default propagation.

I want to call two service methods from a method in UI side expecting those two service method to partcipate in a single transaction as the default propagation is PROPAGATION_REQUIRED . But those two methods are committed to the db independantly. That means if the second method fails, the first one has anyway committed to the db. I have not used try{}catch{{ blocks so any RuntimeException will be bubbled up.

The spring logs are attached. Some lines are removed to reduce the #of lines

[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 

If you want to have one transaction for both method calls, you have to make sure, that the method, where the two methods are called, also have the transaction annotation, like this example:

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

@Transactional
public void method1() {
}

@Transactional
public void method2() {
}

With the help of Spring transaction internals , Open session in view filter I came up with a solution.

According to the first link, in a Spring MVC context a transaction is begun in the controller context and the @Transactional methods in service layer then participates, creates or make another appropriate transaction on top of the already existing transaction. But if the UI layer is something other than Spring MVC this does not happen.

春季交易流程

As shown in this Spring transaction image the transaction advisor is the one who takes the decision whether to commit a transaction or mark for rollback. So if we just let a service method proxy to create a transaction where non exists beforehand, at the end of that very proxy method the advisor takes the decision to commit the transaction. To overcome this we have to create a transaction well before the two service method calls, so those two methods will join the transaction rather than committing by them selves.

In 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 .

See the solution here: I want to... Use JDBC, Spring transactions and @Transactional

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM