Michael Isvy opened SPR-6908 and commented
Overview
It is nice that we can use @Transactional
in integration tests so that transactions are not committed at the end of the test.
However, when the test method calls a method that has a propagation level of REQUIRES_NEW
, the first transaction commits before the second transaction does a rollback. Consequently the database is not in the same state as it was before the test.
Proposal
I would suggest that we add one attribute in the transactionManager as follows:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="lowerPropagationLevels" value="true"/>
</bean>
If a method has a propagation level of REQUIRES_NEW or NESTED, it would automatically lower to REQUIRED
26 votes, 23 watchers
Comment From: spring-projects-issues
Juergen Hoeller commented
This is indeed a problem in integration test scenarios where the test configuration typically means to perform a rollback for any transaction involved, whereas at the moment, the rollback configuration only really applies to the transaction at the outermost level.
I'm not yet sure whether adapting propagation levels is an ideal solution here, but it's certainly one option worth considering. In any case, such a special adaptation mode would have to be activated explicitly, since some tests may rely on the present behavior as well.
Juergen
Comment From: spring-projects-issues
Vasily Ivanov commented
I worked around this problem by converting all service methods that were decoratively setup like this
@Transactional(propagation = REQUIRES_NEW)
public Object doSmth() {
// doSmthThatRequiresNewTx
}
to use TransactionTemplate instead:
private TransactionTemplate transactionTemplate;
public Object doSmth() {
return transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
// doSmthThatRequiresNewTx
}
});
}
Under tests I configure transactionTemplate's propagation behavior to be PROPAGATION_REQUIRED, under real app I configure transactionTemplate's propagation behavior to be PROPAGATION_REQUIRES_NEW. It works as expected. The limitation of this workaround is that under tests it is not possible to assert the fact that inner transaction is not rolledback in an exceptional scenario.
The other solution would be to explicitly delete everything doSmth() does in the database in the @After
method in test. That 'delete' SQL should be ironically run in the new transaction of course, as its results would be otherwise rolled back routinely by Spring's TransactionConfiguration default behavior. :-)
Comment From: spring-projects-issues
Igor Dmitriev commented
Hi, if you have time please pay attention to it.