Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityManager operations order

I have run into interesting issue recently. I use in the project JPA + Hibernate + EJB. The issue concerns saving and deleting entities in the same transaction. Database table which is used has an unique constraint defined on two columns.

What I do is removing entity calling

entityManager.remove();

then the new entity is added with the same values in two properties associated with columns used in the unique constraint but different values in other properties using:

entityManager.persist();

Those two operations are carried out in a single transaction and are executed in the order as presented above. Removal first, addition second. However it seems that the operations are executed in the inverted order as unique constraint is violated. It looks like the new entity is added before removing the previous one.

Obviously, I can call

entityManager.flush()

after removal and then constraint is not violated. However in this case the data is saved to the database before the whole transaction commits. That is not a desirable behavior. If anything goes wrong after flush and transaction will be marked for rollback, the entity will be deleted anyway.

I thought that order of operations is the same as they were added to the transaction. From my example it turns out that it is not.

Is there any way to solve the issue without flushing or committing the transaction after delete?

Thank you.

like image 238
Damian Avatar asked Nov 29 '13 10:11

Damian


People also ask

How does EntityManager work in JPA?

In JPA, the EntityManager interface is used to allow applications to manage and search for entities in the relational database. The EntityManager is an API that manages the lifecycle of entity instances. An EntityManager object manages a set of entities that are defined by a persistence unit.

Which of the following will propagate all EntityManager operations to the relating entities?

With a container-managed entity manager, an EntityManager instance's persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction API (JTA) transaction.

Should EntityManager be closed?

Attempting to close an EntityManagerFactory while one or more of its EntityManager s has an active transaction may result in an IllegalStateException . Closing an EntityManagerFactory should not be taken lightly.


2 Answers

Obviously, I can call entityManager.flush()

Actually you MUST call it.

However in this case the data is saved to the database before the whole transaction commits.

That is wrong: the data is synchronized to DB, but the transaction is still not committed, except you commit it manually and have the control over the DB. If you did not configure anything in the EJBs, and your persistence unit is JTA (see this question with comments), then the transaction will be committed only after the methods returns from the EJB layer.

I thought that order of operations is the same as they were added to the transaction. From my example it turns out that it is not.

No, the JPA specification does not force an implementation to do that. That's why there is a flush() operation.

Is there any way to solve the issue without flushing or committing the transaction after delete?

Yes, as I said use flush(). Also be sure that you use a transactional database engine (e.g. MyIsam in MySql does not support transactions).

like image 59
V G Avatar answered Sep 21 '22 11:09

V G


The solution suggested by Ossama Nasser, is not recommended, since, using different transactions, invalidate the possibility to rollback to initial state if some stuff fail on the second or next transactions.

The entityManager.flush() is the correct solution.

like image 45
Manuel Romeiro Avatar answered Sep 21 '22 11:09

Manuel Romeiro