Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rollback on every checked exception, whenever I say @Transactional

Since the programmer is forced to catch all checked exception, I to throw checked exception in case of any problem. I would like to rollback on any of those expections. Writing rollbackFor=Exception.classon every @Transactional annotation is very error-prone, so I would like to tell spring, that: "whenever I write @Transactional, I mean @Transactional(rollbackFor=Exception.class)".

I know, that I could create a custom annotation, but that seems unnatural.

So is there a way to tell spring how it should handle checked excpetions globally?

like image 501
pihentagy Avatar asked Sep 13 '10 14:09

pihentagy


People also ask

Does @transactional throw exception?

@Transactional only rolls back transactions for unchecked exceptions. For checked exceptions and their subclasses, it commits data. So although an exception is raised here, because it's a checked exception, Spring ignores it and commits the data to the database, making the system inconsistent.

Does @transactional rollback?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

Does transaction rollback on exception?

RollbackException exception is thrown when the transaction has been marked for rollback only or the transaction has been rolled back instead of committed. This is a local exception thrown by methods in the UserTransaction , Transaction , and TransactionManager interfaces.


2 Answers

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?

like image 194
Sean Patrick Floyd Avatar answered Oct 11 '22 20:10

Sean Patrick Floyd


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.

like image 21
axtavt Avatar answered Oct 11 '22 19:10

axtavt