Doorgaan naar hoofdcontent

Using spring's @transactional to only roll back when you really want to

In spring you can use the @Transactional annotation to marcate public methods as transactions.
Any exception thrown in such an exception causes a rollback... Any exception? No, spring only does so on runtime exceptions. Checked exceptions are allowed and do not result in a rollback.
And even then, you can allow some transactions to rollback, or not, with the proper properties for the transactions. For examle, @Transactional(rollbackFor="MyCheckedException.class")will rollback for a specific checked exception, and similarly, you can use @Transactional(noRollbackFor="MyUncheckedException.class") for unchecked exceptions.

Of course, you might want to make it a little simpler on yourself.
This article on stackoverflow shows us a different way: we can use our own transaction handler by overriding spring's.

Let's have a sample interface which defines whether an exception should perform a rollback:

interface ConfigurableRollback
    shouldRollbackOnException();
} 


Assume we have a class like this


public class ConfigurableRollbackTransactionAttributeSource 
    extends AnnotationTransactionAttributeSource {
    @Override
    protected TransactionAttribute determineTransactionAttribute(
            AnnotatedElement ae) {
        TransactionAttribute target = super.determineTransactionAttribute(ae);
        if (target == null) return null;
        else return new RuleBasedTransactionAttribute(target) {
            @Override
            public boolean rollbackOn(Throwable ex) {
                if (ex instanceof ConfigurableRollback) {
                    return ((ConfigurableRollback) ex).shouldRollbackOnException();
                }
                return super.rollBackOn(ex);
            }
        };
    }
}
And we do not use <tx:annotation-driven/> but instead do our own wiring:
<bean id = "txAttributeSource"
    class = "ConfigurableRollbackTransactionAttributeSource " />
<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>

Then presto, we have the option to define by exception what our rollback should be (by having the exception implement ConfigurableRollback's shouldRollbackOnException() method)

Reacties

Populaire posts van deze blog

Spring's conditional annotation with properties

Spring has a nice @Conditional annotation, to have the option to have beans be available in the context depending a specific condition (Of course, this can also be realized by using @Configuration objects, but that's a different post). Ideally, we'd have the option to have a condition evaluate to true or false depending on a property. Sadly, Spring does not support that out of the box. Googling and looking around gives a partial solution, but the complete one here, so we won't forget: /** * Components annotated with ConditionalOnProperty will be registered in the spring context depending on the value of a * property defined in the propertiesBeanName properties Bean. */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { /** * The name of the property. If not found, it will evaluate to false. */ String value(); /** * if the p...

OSGI insights without sonar

So I was on a project without sonar. Oh my. Well, it was an OSGI project, so the problems couldn't be that bad, right? But how good were they (and what things were bad?) I found Stan4j , a code analysis tool for eclipse, which draws nice graphs and can handle osgi pretty well it seems. Now I can see that dependencies/bundle names aren't properly aligned (even though OSGI doesn't complain), etc.

JPA and transactions

So I was working with JPA and transactions. Consider the following: In bean 1, with implicit TX 1, managed entities are loaded/created,and returned in bean 2, with implicit TX 2, entities are modified in bean 3, with NO TX, bean 1 is called, and the results are passed to bean 2. and bean 4 is similar to bean 3, but with it's own transaction, TX3 What happens when bean 3 finishes: are the entities updated? What happens when bean 4 finishes, are the entities updated? The answer to this is simple; entities are managed through a persistance context. That context is tied to the transaction. So in bean 2, there is a difference. When called from bean 3, it runs in a different transaction then bean 1, and thus a different persistance context, and thus the entities are not managed 'by this transaction'.When called from bean 4, it all runs in the same transaction, TX3, and the results are persisted.