Rollback on every checked exception, whenever I say @Transactional
Custom Shortcut Annotations
I know, that I could create a custom annotation, but that seems unnatural.
No, this is exactly the use case for a Custom Annotation. Here's a quote from Custom Shortcut Annotations in the Spring Reference:
If you find you are repeatedly using the same attributes with @Transactional on many different methods, then Spring's meta-annotation support allows you to define custom shortcut annotations for your specific use cases.
Sample Code
And here's a sample annotation for your use case:
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Transactional(rollbackFor=Exception.class)public @interface MyAnnotation {}
Now annotate your services and / or methods with @MyAnnotation
(you'll think of a better name). This is well-tested functionality that works by default. Why re-invent the wheel?
Approach with custom annotation looks good and straightforward, but if you actually don't want to use it, you can create a custom TransactionAttributeSource
to modify interpretation of @Transactional
:
public class RollbackForAllAnnotationTransactionAttributeSource extends AnnotationTransactionAttributeSource { @Override protected TransactionAttribute determineTransactionAttribute( AnnotatedElement ae) { TransactionAttribute target = super.determineTransactionAttribute(ae); if (target == null) return null; else return new DelegatingTransactionAttribute(target) { @Override public boolean rollbackOn(Throwable ex) { return true; } }; }}
And instead of <tx:annotation-driven/>
you configure it manually as follows (see source of AnnotationDrivenBeanDefinitionParser
):
<bean id = "txAttributeSource" class = "RollbackForAllAnnotationTransactionAttributeSource" /><bean id = "txInterceptor" class = "org.springframework.transaction.interceptor.TransactionInterceptor"> <property name = "transactionManagerBeanName" value = "transactionManager" /> <property name = "transactionAttributeSource" ref = "txAttributeSource" /></bean><bean class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor"> <property name="transactionAttributeSource" ref = "txAttributeSource" /> <property name = "adviceBeanName" value = "txInterceptor" /></bean>
Also you need <aop:config/>
or <aop:aspectj-autoproxy />
.
However note that such overrides may be confusing for other developers who expect a normal behaviour of @Transactional
.
You can:
- catch and wrap the checked exception into an unchecked exception -
throw new RuntimeException(checkedException)
- create a proxy around the method, using
MethodInterceptor
(or@AroundInvoke
, or any other means to create aspects in spring), declare it to be executed before the<tx:annotation-driven />
by specifyingorder="1"
andorder="2"
and catch and wrap there.