0

I'm using EJB3 and JPA2 in a project containing several modules. Lately i have noticed that the DB-records won't rollback on exception. After doing some research i found that entity manager commits the transaction on flush immediatly even before the method ends, so that it can't rollback on exception.

I inject entity manager using

@PersistenceContext
private EntityManager entityManager;

To create a new record is persist and flush beeing called in the same class

entityManager.persist(entity);
entityManager.flush();

Even if i call throw new RuntimException("") right after flush, it wont rollback. On debug after flush is invoked i can select the DB-record with a database tool, before the method ends.

I already checked the persistence.xml and found nothing unusual. I dont use any other specifig configuration. I'm out of ideas what might cause this behavior. I appriciate any clue.

mersen
  • 51
  • 3
  • 1
    Can you double-check auto-commit? http://stackoverflow.com/questions/13441043/entitymanager-flush-commits-the-transaction-in-a-java-web-service – kervin Sep 30 '15 at 13:13
  • Thanks so much kervin. That was the solution. I still dont understand why exactly this behavior caused but i am gonna read some documentation. – mersen Sep 30 '15 at 14:28

1 Answers1

0

You need to specify transaction boundaries, otherwise a new transaction will be opened and commited after each data manipulation query (INSERT, UPDATE, DELETE). As em.flush() will trigger such SQL query to be executed, it will open an implicit transaction and commit it if the SQL is successful, rollback in case of error.

In order to set transaction boundaries and make a RuntimeException trigger a rollback, the best option is to call entityManager methods from an EJB object. You must use a JTA datasource, not RESOURCE_LOCAL. If you don't use JTA datasource, you need to manage transactions by yourself, ie. by using entityManager.getTransaction() object.

Outside of an EJB, or with non-JTA datasource, you do not have any transaction open, unless you start it yourself by calling entityManager.getTransaction().begin(). However, in this way, your transaction will not be rolled back when Exception is thrown. Instead, you must roll back in catch block. This is mostly outside of Java EE container, in a Java SE application. In Java EE, I strongly suggest to use JTA datasource. Example:

public class NotAnEJB {
  public persistEntity(EntityManager em, MyEntity entity) {
    em.getTransaction().begin();
    try {
      em.persist(entity);
      em.flush();
      if (shouldFail()) {
        throw new RuntimeException();
      }
      em.commit();
    } catch (Exception e) {
      em.rollback();
    }
  }
}
OndroMih
  • 7,280
  • 1
  • 26
  • 44