Issue Type: Bug Bug
Affects Versions: 3.6.7
Assignee: Unassigned
Components: core
Created: 06/Jul/12 8:19 AM
Description:

Here are the requisites to reproduce the bug:

  • Have a proxied entity (OneToOne association with Lazy fetch)
  • Using the @Version attribute on the entity being proxied
  • Locking the proxied entity in WRITE or OPTIMISTIC_FORCE_INCREMENT

The first time, the version won't be incremented. But later calls to the same code will increment the version.

I checked a couple of things and I think the problem come from:

  • when acquiring a lock, if the object is a proxy, hibernate will get the entity
    DefaultLockEventListener#onLock:
    Object entity = source.getPersistenceContext().unproxyAndReassociate( event.getObject() );
  • If it is a proxy, hibernate will load the entity with a simple LoadEvent (LockMode.NONE used - SessionImpl#immediateLoad)
  • Further, Loader#instanceNotYetLoaded will be reached and especially this:
    LockMode acquiredLockMode = lockMode == LockMode.NONE ? LockMode.READ : lockMode;
    as lockMode was NONE, it will be READ on this entity
  • we come back to DefaultLockEventListener#onLock and we go to:
    upgradeLock( entity, entry, event.getLockOptions(), event.getSession() );
  • there, we compare our lockMode (WRITE) with the lockMode of the entity (READ if it was a proxy). As the level of READ is 5 and the level of WRITE (or OPTIMISTIC_FORCE_INCREMENT for hibernate) is 4, nothing is done.
  • the second time we run the same code (or if the entity was not a proxy), the lockMode of the entity will be NONE (it is done at the end of a transaction with StatefulPersistenceContext#afterTransactionCompletion). And the upgradeLock will indeed perform:
    persister.lock( entry.getId(), entry.getVersion(), object, lockOptions, source );
  • from there, an EntityIncrementVersionProcess will be register and it will be fired during the ActionQueue$BeforeTransactionCompletionProcessQueue#beforeTransactionCompletion

The problem is that the application code is rather simple:

Entity child = entityManager.find(Entity.class, id);
entityManager.lock(child.getParent(), LockModeType.WRITE);

And I don't see a workaround for this (without using the LockMode.PESSIMISTIC_FORCE_INCREMENT).

Project: Hibernate ORM
Labels: hibernate locks proxy
Priority: Major Major
Reporter: Michaël Chagnon
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators.
For more information on JIRA, see: http://www.atlassian.com/software/jira