I found a problem with the merge method of EntityManager: when trying to merge a detached entity which has been deleted by another transaction, the merge method silently creates a new instance back in the database instead of throwing an exception to indicate a violation of optimistic lock control. I consider this is a bug, and when I searched the Hibernate JIRA, I found someone reported this bug before, but it was rejected by a responder saying that it was the expected behavior.
The problem can be illustrated by the following code fragments:
em.getTransaction().begin();
Employee emp1 = em.find(Employee.class, pk1);
// do some updates to emp1 here, then commit the txn
em.getTransaction().commit();
// emp1 is now in detached mode because the txn is committed
// start another transaction
em = factory.createEntityManager();
em.getTransaction().begin();
Employee emp2 = em.find(Employee.class, pk1);
em.remove(emp2); // delete this entity and commit the transaction
em.getTransaction().commit();
// the entity should now be removed physically from the database
// now start another transaction again
em = factory.createEntityManager();
em.getTransaction.begin();
// merge emp1 to the persistence context of the new txn
emp1 = em.merge(emp1);
em.getTransaction().commit();
// an exception should be thrown either in the merge or commit
// because of a violation of optimistic lock control
However, the Hibernate entity manager doesn't do so to throw an exception. Instead, it creates a new instance back in the database silently.
If you slightly modify the above example to do an update in the second transaction instead of doing a remove, an OptimisticLockException will be thrown in the third transaction. This behavior is correct and expected, but I don't know why it doesn't do so for a deleted entity.
Can anyone tell me whether my understanding of the EJB3 merging mechanism correct and thus it is a bug in Hibernate, or I am wrong and that is the expect behavior of merge?
|