Spring @Transactional & Exception

Spring Transactional Annotation & Exception


What is Transaction?

The transaction is unit work which will success or fails as the unit. So suppose we are dealing with two accounts for transfer money from one to another.  Now if Money from one account is already debited but while it is credited to an another account there was Exception so the ideal scenario would be debited action should rollback. Otherwise, it would be an Inconsistent state.

So if we use Transaction in our business logic we can ensure, logic under the Transaction work as a unit it will be rollback if anything found wrong.

In one word.

Either Unit of work Succeeds completely or failure completely no intermediate state.


Now the question comes How we can handle Transaction.

There are two ways to Handle it

BMT: Bean managed Transaction.
CMT: Container Managed Transaction.



BMT: If we need a finer control over business logic or want to introduce savepoints this type of technique should be adopted where bean provider has a responsibility to start, commit, rollback the transaction.

CMT: If we want to delegate the responsibility to container we use it. Sometimes we called it Declarative Transaction.


We all know in Spring using @Transactional annotation we can adopt Declarative transaction technique.

In this article, I will not show how to configure it but tell about the precaution you want to take while using @Transactional annotation.

Study the pseudo code.
@Transactional
pbublic void transferMoney(Account to,Account from,int amount) throws Exception{
        debiFromAccount(to,amount)
        creditFromAccount(from,amount);
       
    }
   
    public debiFromAccount(Account to,int amount){
        //do staff and debited money from data base
    }
   
    public creditFromAccount(Account from,int amount)throws Exception{
        //do straff
        throw new EXception("Error during credit");
    }



Now do a dry run
If Account to initial balance is 1000
Account from is 500
Transfer amount : 100


After error occurred in creditFromAccount(Account from,int amount) what will be the output you expected?

To : 1000
From : 500

Afterall I use @Transactional so in case of Exception it should be rolled back automatically right.

But unfortunately it left a inconsistent state

Output is like

To : 900
From : 500


So obviously you will ask me Why, what is going on here?

Let me clear you, @Transactional only rollback transaction only for the unchecked exception but for checked Exception and it’s subclass it commits data. So although an Exception raised here but as it is a Checked Exception, Spring simply ignores it and commit the data to the database so the system goes inconsistent.

Spring documentation says that,



While the EJB default behavior is for the EJB container to automatically roll back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this.

So pay attention to the last line “it is often useful to customize this”

So how can we customize it?

It is very simple just use following with @Transactional

@Transactional(rollbackFor = Exception.class)
So if you throw an Exception or Subclass of Exception always use the above with @Transactional annotation to tell Spring to rollback transaction in case for Checked Exception occur.