JavaTechnical
JavaTechnical

Reputation: 9357

How to rollback transaction in JPA?

I have an EntityManager object maintained by the Spring framework and I inject it in whatever DAO class I want using the @PersistenceContext annotation like this..

@PersistenceContext(unitName="entityManager")
private EntityManager em;

I use those DAO classes to save in the database something like this..

class MyClass
{
    @Resource(name="myDao")
    private MyDao dao;

    @Resource(name="myAnotherDao")
    private MyAnotherDao anotherDao;

    public void save(String s1,String s2)
    {
        try
        {
             MyEntity m=new MyEntity();
             m.setName(s1);
             // .. and so on ..

             XYZ x=new XYZ();
             x.setDEF(s2);

             anotherDao.save(x);

             m.setXYZ(x);
             // .. some other stuff .. //
             dao.saveEntity(m);
         }
         catch(Exception e)
         {
             // I would like to rollback the transaction
         }
     }
}

Now, both the daos here use the same EntityManager injected through @PersistenceContext(unitName="entityManager"). Now, if an exception occurs after setXYZ(), then I would like to rollback even the saved XYZ entity. But, how do I get the EntityManager from that?

If all the daos hold the same object, then can I just call the getTransaction().rollback() method of the EntityManager class? Does the getTransaction() return a new transaction or any transaction that is currently associated with EntityManager?

Upvotes: 9

Views: 58932

Answers (4)

mohammed saquib
mohammed saquib

Reputation: 170

To rollback a transaction you can use @Transaction annotation. You can either implement it on method level or class level.

Method level example:

@Transactional(rollbackFor = {YourDesiredException.class, SomeOtherException.class})
void yourMethod(datatype param1,...){
     //your transaction that may throw exception
}

Class level example:

@Transactional(rollbackFor = {YourDesiredException.class, SomeOtherException.class})
public class SomeClass throws YourDesiredException{

void method1(){
    //transaction 1
}

void method2(){
   //transaction 2
}

}

Class level @Transactional(rollbackFor = Exception.class) will rollback all the transaction happened at the class level where as method level will only rollback transactions happened in that method.

PS: Do not use try-catch block (ie, do not catch the exception) and let the exception propagate.

Upvotes: 2

PKumar
PKumar

Reputation: 556

It will be rollback once you throw any RuntimeException from a method marked as @Transactional like below:

By default, all RuntimeExceptions rollback transaction where as checked exceptions don't:

@Transactional(rollbackFor={MyRuntimeException.class, AnotherRuntimeException.class})
public SomeVal someTransactionalMethod(){
   ...
}

Upvotes: 9

huangyp
huangyp

Reputation: 129

  1. If you used Spring AOP to manage transaction, and the configuration and annotation is used right, the default effect is the transaction would be rolled back when the runtime exception occurs.

  2. If you managed transaction manually, you can roll back transaction like this:

    EntityManager em = createEntityManager();
    
    try {
    
        em.getTransaction().begin();
        // Do something with the EntityManager such as persist(), merge() or remove()
        em.getTransaction().commit();
    } catch(Exception e) {
    
        em.getTransaction().rollback();
    }
    
    em.close();
    

See more at: http://en.wikibooks.org/wiki/Java_Persistence/Transactions http://www.developerscrappad.com/547/java/java-ee/ejb3-x-jpa-when-to-use-rollback-and-setrollbackonly/#sthash.jx3XlK5m.dpuf

Upvotes: 12

JB Nizet
JB Nizet

Reputation: 692211

Just don't catch the exception. Let it bubble. Spring will automatically rollback the transaction if a runtime exception is thrown from a transactional method call. And the caller will at least know that something bad happen, instead of thinking everything went fine.

Anyway, your catch block will probably not catch anything, because most of the exceptions happen at flush time, and flush mainly happens just before commit, in the Spring transaction interceptor. Remember than persisting an entity doesn't execute an insert query immediately. It just tells Hibernate that, before the end of the transaction, an insert will have to be executed.

Upvotes: 1

Related Questions