Now it amazes me, so I will share my conclusions.
First, some background:
- We use Hibernate 3.5.2 and EhCache 2.7.0
- There is only one database (the other is read-only, but it does not use caching because it is updated externally) and an instance of a single cache (without clustering)
- The problem occurs when updating an object associated with InheritanceType.JOINED and CacheConcurrencyStrategy.READ_WRITE (but not when switching to NONSTRICT_READ_WRITE). In addition, judging by the verification of the code, this will happen during deletion.
What I found when debugging Hibernate and EhCache code:
- Hibernate EntityUpdateAction (in execute ()) calls EntityRegionAccessStrategy.lockItem ()
- An EhCache implementation (in AbstractReadWriteEhcacheAccessStrategy) changes the mapping for a given key from a cached object to a lock
- Hibernate detects that an object maps to more than one table, and therefore invalidation caching is required (see AbstractEntityPersister.isCacheInvalidationRequired ())
- It goes to the persister.getCacheAccessStrategy () call. remove (), which in the EhCache implementation removes the mapping for the given cache key. However, while Hibernate expects this to actually delete the cached object, with EhCache it will remove the lock (which was placed there in step 2).
- After the transaction is completed in EntityUpdateAction.doAfterTransactionCompletion (), Hibernate detects that a cache invalidation is required, and proceeds to calling unlockItem (), which does not work if there is no mapping for the specified cache key, as a result of which you described an error message
It seems to me that this is a problem in the implementation of EhCache lockItem () and unlockItem () (in the case of READ_WRITE). It should not replace the actual elements with locks, but store locks separately. At least you could say that Hibernate and EhCache are not 100% compatible in this scenario.
A few final notes:
- This error seems to be harmless and can be safely suppressed using the log4j configuration.
- I managed to repeat this in another scenario (which boils down to the same lock / delete / unlock sequence). This time, instead of shared inheritance, the original SQL triggered the deletion. Everything else is almost the same.
- The corresponding bits of the Hibernate and EhCache code are: EntityRegionAccessStrategy, EntityAction, CollectionRegionAccessStrategy, CollectionAction and their associated implementations / extensions of specific classes.
NTN
source share