Wednesday, 8 February 2017

Spring Transactions management tips

In this article I will describe ways of managing transactions in Spring. And will share some useful notes based on my experience

Here is two ways to manage transactions in spring:

1) Programmatic transaction with TransactionTemplate class

this means that you have to manage the transaction with the help of programming. That gives you flexibility, but it is difficult to maintain.

-here is typical example:

TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<object>() {
    public Object doInTransaction(TransactionStatus status) {
        // do stuff
    }
});

-be aware that A RuntimeException thrown by the callback is treated as a fatal exception that enforces a rollback. Such an exception gets propagated to the caller of the template (see TransactionTemplate source in references). 

In example bellow even if all records will be saved successfully and only last entry will raise any Exception entire batch will be rolled back:


for(Records r: records){
    txTemplate.execute(new TransactionCallback<object>() {
        public Object doInTransaction(TransactionStatus status) {
           process(r);
        }
    });
}

2) Declarative transaction with @Transactional annotation

this means you separate transaction management from the business code. You only use annotations or XML-based configuration to manage the transactions

-default propagation  is Propagation.REQUIRED

-default configured to rollback just Unchecked exceptions (ex RuntimeException), to rollback Exception need to use it like this:

@Transactional(rollbackFor = Exception.class)

-also method should be public, spring will wrap your method with proxy on context start and will add commit/rollback logic, that is how transnational annotation magic works.

 -call to transnational method should be made from different class not from the same class, it is limitation of CGLIB (library that is doing method wrapping by the way you can use AspectJ)

-exception saying that "the transaction was marked as rollback only" it is because setRollbackOnly() method was called by exception (by the way you can call it too using previous approach), you can prevent it like this, or start new transaction for each part that should be handled independently

@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)

-the Service is the best place for putting @Transactional

References:
16. Transaction Management
TransactionTemplate.java source code

No comments:

Post a Comment