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