Hi all,
I've got the following (relevant) code snippets right now:
Code:
final Parent parent = em.find(Parent.class, parentId);
em.lock(parent, LockModeType.OPTIMISTIC);
and later in the code i call:
Code:
em.remove(parent);
This results in an OptimisticLockException, although no other Transaction modifies the same data.
The cause is of this failure is in org.hibernate.action.internal.EntityVerifyVersionProcess (hibernate version 4.2.13)
Code:
Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
if ( !entry.getVersion().equals( latestVersion ) ) {
throw new OptimisticLockException(
object,
"Newer version [" + latestVersion +
"] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) +
"] found in database"
);
}
latestVersion is null in this case (the entry is removed), causing the exception to be thrown. My questions:
- Is this the expected behaviour given the JPA spec? I've checked the spec, but it doesn't say anything about this behaviour specifically AFAICS.
- Is there a way to clear the lock in this case (i'd rather would like to avoid not call em.lock in the first place). lock(entity, NONE) does not clear the lock, so that's not an option. If I do this, em.getLockMode(parent) still returns OPTIMISTIC, which is not what I would expect. Interestingly, a call to em.detach() still results in the entity being checked for an Optimistic lock.
Update: I've just created the following test-case:
Code:
@Test
public void testRemoveWithReadLocking() {
final long parentId1 = createTestData(1);
final long parentId2 = createTestData(2);
final long parentId3 = createTestData(3);
final long parentId4 = createTestData(4);
final EntityManager em1 = factory.createEntityManager();
em1.getTransaction().begin();
final TypedQuery<Parent> query = em1.createQuery("select p from Parent p", Parent.class);
query.setLockMode(LockModeType.OPTIMISTIC);
for (final Parent parent : query.getResultList()) {
em1.remove(parent);
}
em1.getTransaction().commit();
em1.close();
}
This also results in a OptimisticLockException, which would seem really weird. This would mean I cannot perform an optimistic lock in a query and in the loop e.g. determine to remove the entity or update an entity. My conclusion is, the existance of a lock for an entity is ignored by:
- EntityManager.detach() (and clear() probably also)
- EntityManager.remove()
- EntityManager.lock()
which is not what I would expect.