Spring’s @Transactional does not rollback on checked exceptions

Wissenswertes
34 Kommentare

We’re using the Spring Framework in most of our applications (and thus also in the Catalysts Platform) and are really satisfied with it.

One of the big advantages is the the declarative transaction handling using the @Transactional attribute.

import org.springframework.transaction.Transactional;

@Transactional
public class MyService implements IMyService {
  public List getResults () {
    // do something
  }

  public void foo() {
    throw new java.lang.UnsupportedOperationException();
  }

  public void bar() {
    throw new java.lang.Exception();
  }
}

That simple annoation on class managed by a Spring ApplicationContext causes all method calls onto that service to be bound to a transaction. The transaction is committed after the method call has left the service again and it’s rollbacked for the case an exception is thrown (e.g. after calling the (quite silly) method foo()).

But be careful: Only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked by default. For the case, a checked exception is thrown, the transaction will be committed!

The Spring documentation explains that as follows:

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.

And that customization can be done very easily by just adding the parameter rollBackFor to the @Transactional attribute:

import org.springframework.transaction.Transactional;

@Transactional(rollbackFor = Exception.class)
public class MyService implements IMyService {
  public List getResults () {
    // do something
  }

  public void foo() {
    throw new java.lang.UnsupportedOperationException();
  }

  public void bar() {
    throw new java.lang.Exception();
  }
}

In that case, the transaction will even be be rollbacked on a call to the method bar().

Vorheriger Beitrag
Actionscript Code Dependency Metrics mit Asycle
Nächster Beitrag
2. Wispri: Ein alltägliches Problem: wieviel Aufwand ist das?

Related Posts

Highly available webapps with Java and Spring – Part 1

High availability and fault tolerance are frequently important requirements for customers. By thinking ahead and using the right technologies we at Catalysts can fulfill these requirements to boost your products performance and ensure productivity.

Weiterlesen

34 Kommentare. Hinterlasse eine Antwort

Nice article! Very helpful)

Antworten

Great!

Good Article. Thanks for it.

Antworten

Why would you ever want throw a checked exception from the service layer up? What do you think the caller will do with them!?

Normally you would deal with these bad checked exceptions within the service, so the caller does not have to clean the mess + if you really want to roll back on this checked exception, rethrow it as a Runtime (unchecked)

/Toly

Antworten

Well the problem of unchecked exceptions is that the caller never knows what can happen on a certain call and you can’t force him to react on it. Suppose you have a form with a couple of input fields and want to validate all the data. Of course you do that inside the service layer, or maybe even in the dao layer, and then e.g. use springs binding framework to throw a BindException (which is a checked exception). Now of course I could convert that later into a RuntimeException and throw that out to the view layer but even in that case the caller has to react on it, and e.g. show some error message. That’s much clearer if it’s a checked excpetion that forces the client to create a try/catch block. @Toly

Antworten

“@Transactional(rollbackFor = Exception.class)” – Does this mean if all the service methods throw a subclass of any checked exception, they will all be rolled back?

Antworten

Sorry unchecked exception

Antworten

My problem is the other way round. I have rollbackFor=MyException.class …. however, my transaction is being rolled back even for Exceptions that are not of type MyException or one of its sub classes. Any help on this?

Antworten

Hi,

Nice article. Just a thought. @ApplicationException(rollback=true) on a user defined exception would do the same isnt it? Or any runtime exception will automatically roll back a transaction.

Antworten

Nice Article , very userful

Antworten

Hi

Nice article, but would this work for below requirement.

Once a transaction is started I saved many records in to many tables and if any exception ocurrs it should rollback all the records from database.

Antworten

@chinna, yes of course that would work, that’s the intention of all that stuff

Antworten

hi,
i am throwing checked exception . @transactional(rollbackFor=Exception.class) also added but still my transaction is getting commited.
pls help .

Antworten

@tripty What propagation do you have? What is not being rolled back? Are you also calling the method directly? If you could show the class and the calls, it could clarify things. If you are calling just the method directly (ie. it is not a nested txn) then you should have a full rollback.

Antworten

Just remember that rollbackFor will only work for exceptions that are not checked in your transaction method. for e.g if you have @Transactional(rollbackFor=Exception.class) and within your method if you wrap try/catch block for Exception, rollback will not occur.

Antworten

What about conflicting rollbackFors? Say service A calls service B. Service A says to rollback on ABCExceptions (which extend Exception) and service B says to rollback on Exception. Does service B’s rollbackFor override service A’s?

Antworten

@Ben: by calling Service A you enter the transaction, therefore the rules from that annotation apply. you could open a new subtransaction on Service B by adding requires=new on the @Transactional, but in your case the rule from the outer service applies

Antworten

how to do with anotations?

Antworten

Thank you so much. You saved my day. I am struggling to find out why the transaction is not being rollbacked. Once I set what you recommended, it started to rollback when there is an error.

Antworten

[…] Transaction – automatic rollback of previous db updates when one db update failesSpring’s @Transactional does not rollback on checked exceptionsTransaction strategies: Understanding transaction […]

Antworten

thanks a ton!! very good article

Antworten

Thanks a lot! Saved my day

Antworten

This is what i am looking. Good explanation.

Antworten

Hi,I am also using the @Transactional but it is not rollbacking when exception is occured
for checked or unchecked exception the below code must rollback the insertion but its not.

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public void saveEmployeeAndCustomer(EmployeeVo employeeVo) {
int saveEmployee = saveEmployee(employeeVo);//inserting in employee table
int a=10/0; // this will generate umchked exception
int saveCustomer = saveCustomer(employeeVo);//inserting in customer table
if(saveEmployee==1 && saveCustomer==1){
System.out.println(“saved In both table successfully”);
}else{
System.out.println(“Unable to save In both table”);
}

Above code will insert data in employee table .
But i was expecting it should not insert into any of the table.

Antworten

    Vishal, are you sure the transactional wrapping is really applied? If using proxying then you must make sure you are not calling this method from another method of the the same class.

    Antworten

with below config…

PROPAGATION_REQUIRED,-Exception
PROPAGATION_REQUIRED,-Exception
PROPAGATION_REQUIRED,readOnly

I am using @Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class )

It is not rolling back. Please help. URGENT.

Antworten

Hi
I am calling two dao methods(first update and then insert) inside one method. when second method is throwing null pointer exception, first method does not roll back. I have tried @Transaction(rollbackFor = Exception.class), it does not work.
Please help.

Antworten

Hi, In my code there are 3 inserts to database. If the third one fails, all the first 2 transactions will be rolled back.
But if an exception occurs in a non database code after all 3 inserts are completed it is not rolled back.
@transactional(rollbackFor=Exception.class)
public void process(){
dbinsert1();
dbinsert2();
dbinsert3();
triggeremail();

}

Antworten

i have a problem …if checked exception raise from dao class and not handle on controller or anywhere else in spring then what happen??

Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Bitte füllen Sie dieses Feld aus
Bitte füllen Sie dieses Feld aus
Bitte gib eine gültige E-Mail-Adresse ein.
Sie müssen den Bedingungen zustimmen, um fortzufahren

Menü