3

I would like Spring to rollback a transaction on methods annotated with @Transactional in case the method throws a checked exception. An equivalent of this:

@Transactional(rollbackFor=MyCheckedException.class)
public void method() throws MyCheckedException {

}

But I need this behavior to be default for all @Transactional annotations without the need to write it everywhere. We are using Java to configure Spring (configuration classes).

I tried the configuration suggested by spring documentation, which is only available in XML. So I tried to create this XML file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd">

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="*" rollback-for="com.example.MyCheckedException" />
    </tx:attributes>
</tx:advice>

</beans>

... and import it via @ImportResource. Spring did recognize and parse the file (I had some errors in it at first), but it doesn't work. The behavior of @Transactional has not changed.

I also tried defining my own transaction property source, as suggested in this answer. But it also used the XML configuration so I had to transform it into Java like this:

@Bean
public AnnotationTransactionAttributeSource getTransactionAttributeSource() {
    return new RollbackForAllAnnotationTransactionAttributeSource();
}

@Bean
public TransactionInterceptor getTransactionInterceptor(TransactionAttributeSource transactionAttributeSource) {

    TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
    transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);

    return transactionInterceptor;
}

@Bean
public BeanFactoryTransactionAttributeSourceAdvisor getBeanFactoryTransactionAttributeSourceAdvisor(TransactionAttributeSource transactionAttributeSource) {

    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();

    advisor.setTransactionAttributeSource(transactionAttributeSource);

    return advisor;
}

This also didn't work - Spring kept using its own transaction property source (different instance than the one which was created in the configuration).

What is the correct way to achieve this in Java?

1
  • Well if you only configure half of the things then obviously it will not work. You also have to disable @EnableTransactionManagement and add everything that that annotation does... Commented Nov 8, 2016 at 20:54

1 Answer 1

4

You should rather implement own annotation - reference

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=MyCheckedException.class)
public @interface TransactionalWithRollback {
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes I'm also considering this option but what I don't like about it is that the custom annotation has to be used everywhere instead of the standard @Transactional annotation and someone somewhere in the future can forget this and they will create an error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.