5
votes

A client application supplies a stale entity which is to be merged by Hibernate. Taking a very simple example.

public Entity update(Entity entity) {
    return entityManager.contains(entity) ? entity : entityManager.merge(entity);
}

Entity is a detached, stale entity supplied by a web application, for example. The method is executed in an active JTA transaction (or resource local).

Optimistic locking has been enabled by introducing a @Version field in the entity given.

When an entity to be merged had already been deleted, javax.persistence.OptimisticLockException is expected to be thrown which does not happen. Hibernate performs INSERT instead which is completely unexpected. Inserting a stale entity instead of throwing the javax.persistence.OptimisticLockException is something going against locking.

"Insert or update" is a story apart which should be suspended by throwing the javax.persistence.OptimisticLockException, if a stale or deleted (nonexistent) entity is passed to merge(), if optimistic locking is implemented.

EclipseLink throws the javax.persistence.OptimisticLockException as expected in case a stale or deleted / nonexistent entity is passed to merge().

Is there a way to make Hibernate throw the javax.persistence.OptimisticLockException, when a stale or nonexistent entity is passed to merge()?

I expect there should be some configurable property in persistence.xml to apply it globally application-wide or annotations to apply it to a specific entity.

I am currently using Hibernate 5.0.5 final.


Updated to Hibernate 5.0.6 final.

1
This is a long-standing Hibernate bug. You can vote for it: hibernate.atlassian.net/browse/HHH-1661JB Nizet
The issue is about a decade old.Tiny
I think, a new, fresh issue should be created. That issue report is very unlikely to be taken into account as it is quite old. It is a critical bug that cannot be taken lightly and needs to be fixed as soon as possible.Tiny
It has been updated for Hibernate 5 and thus kept in the open bugs when the big JIRA cleaning was made, is precise, has votes, and a reproducible test case. Opening a new identical bug will either dissolve the bug or the attention, or be marked as a duplicate.JB Nizet

1 Answers

0
votes

Try EntityManager.refresh instead EntityManager.merge, and verify if entity has a id value, if yes set new values and after EntityManager.merge, if not the entity has been deleted

something like this

public Entity update(Entity entity) {

    entityManager.refresh(entity);

    if (entity.getId() != null) {
        // my entity is in database
        // set my changes in entity
        return entityManager.merge(entity);
    } else {
        // my entity has been deleted
        return null;
    }
}