Order of operations EntityManager

advertisements

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.


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).