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.
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.
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.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With