Wednesday, 13 August 2014

@Transactional

When connecting to a database a transaction is often required.  There are a number of ways of doing this but the most common is to use Spring transactions.

pom.xml

This dependency is needed to allow transactions

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<scope>compile</scope>
</dependency>


Spring Context

In the spring configuration an entity manager is necessary (see Entity Manager blog entry)

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

<!-- Define a transaction manager so that the @TransactionConfiguration and @Transactional can be used -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Proxy Class

The above combination will allow spring to create proxy classes which create a transaction before passing into the @Transactional method.  This means that because it is a proxy @Transactional doesn't work for any 'internal' call within the your class.  Eg even if a method is public if it is called from within the same class it won't pass through the proxy and therefore won't have a transaction.
If this type of behaviour is required then the transactions can be wired using AOP and the transaction code is created at compile time rather than a runtime proxy.

Exception Handling

Normal exceptions can be caught using the normal try - catch but if the database isn't there at all then there is an exception generated in the proxy before the method code is called.  The exception is a 
    org.springframework.transaction.CannotCreateTransactionException

To catch the exception within the same method as the actual database errors the transaction can be created a different way.

Programmatic Transactions

A programmatic transaction can be created using the TransactionTemplate in which case the TransactionException (CannotCreateTransactionException) can be caught in the same place.

    try
    {
        transactionTemplate.execute(new TransactionCallbackWithoutResult()
        {
            @Override
            protected void doInTransactionWithoutResult(final TransactionStatus status)
            {
                 // Do something to the database here
            }
        });
    }
    catch (PersistenceException | TransactionException e)
    {
        LOG.error("Database Error", e);
    }

There is also a TransactionCallback() which returns the object from the database whereas the one above doesn't do that.

The transactionTemplate can be created in spring configuration,

    <property name="transactionTemplate">
        <bean class="org.springframework.transaction.support.TransactionTemplate">
            <constructor-arg ref="transactionManager" />
</bean>
    </property>






No comments:

Post a comment