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?

Community
  • 1
  • 1
Jardo
  • 1,939
  • 2
  • 25
  • 45
  • 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... – M. Deinum Nov 08 '16 at 20:54

1 Answers1

4

You should rather implement own annotation - reference

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=MyCheckedException.class)
public @interface TransactionalWithRollback {
}
maszter
  • 3,680
  • 6
  • 37
  • 53
  • 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. – Jardo Nov 08 '16 at 20:47