1

Hibernate succeeded to retrieve Query Result from cache, then it failed to retrieve Entities from Cache, it executed a single Query for every row.

I debugged org.hibernate.event.internal.DefaultLoadEventListener, and in my case persister.hasNaturalIdentifier() returned false, so looks like entities are never cached.

I was expecting that the ID should be used as a default KEY.

protected Object doLoad(
            final LoadEvent event,
            final EntityPersister persister,
            final EntityKey keyToLoad,
            final LoadEventListener.LoadType options) {
        Object entity = loadFromSessionCache( event, keyToLoad, options );

        entity = loadFromSecondLevelCache( event, persister, options );
        if ( entity != null ) {
        }
        else {
            entity = loadFromDatasource( event, persister, keyToLoad, options );
        }    
        if ( entity != null && persister.hasNaturalIdentifier() ) { 
        event.getSession().getPersistenceContext().getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad(
                    persister,
                    event.getEntityId(),
                    event.getSession().getPersistenceContext().getNaturalIdHelper().extractNaturalIdValues(
                            entity,
                            persister
                    )
            );
        }        
        return entity;
    }

SO after

1_ the loadFromSecondLevelCache Faileds

2_ it load from Datasource,

3_ then it should put the Entity in the Cache wich is not possible because persister.hasNaturalIdentifier() returned false

If i am wrong where is the hibernate sequence for the insert of the Entity to the cache after the load?

After some search my problem is exactly this secondlevelcache

And it also a duplicate of this coherence-hibernate-integration/1.0.0/secondlevelcache

So the real problem is

During the creation of the cacheKey hibernate use persister.getRootEntityName()

final CacheKey cacheKey = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
    if ( session.getPersistenceContext().wasInsertedDuringTransaction( persister, id ) ) {
        persister.getCacheAccessStrategy().update(
                        cacheKey,
                        persister.getCacheEntryStructure().structure( entry ),
                        version,
                        version
                );
    }

But during the retrive it use persister.getEntityName() !!!!

protected Object loadFromSecondLevelCache(
            final LoadEvent event,
            final EntityPersister persister,
            final LoadEventListener.LoadType options) {

        final SessionImplementor source = event.getSession();
        final boolean useCache = persister.hasCache()
                && source.getCacheMode().isGetEnabled()
                && event.getLockMode().lessThan( LockMode.READ );

        if ( !useCache ) {
            // we can't use cache here
            return null;
        }

        final SessionFactoryImplementor factory = source.getFactory();
        final CacheKey ck = source.generateCacheKey(
                event.getEntityId(),
                persister.getIdentifierType(),
                persister.getEntityName()
        );
Community
  • 1
  • 1
Nassim MOUALEK
  • 4,702
  • 4
  • 25
  • 44

2 Answers2

0

Hibernate searches the cache by ID, not by natural-id, check this call:

entity = loadFromSecondLevelCache( event, persister, options );

In your case it may be that the cache entry got invalidated by a pending concurrent entity modification.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • the first time this should fails, but after the loadFromDataSource, hibernate should put the Entity to the cache wich is not done, i verified that with SelectableConcurrentHashMap.put(Object key, Element element) wich is never called – Nassim MOUALEK Jan 02 '15 at 20:13
  • Maybe it's a bug. Write a small UT and file a Hibernate issue. – Vlad Mihalcea Jan 02 '15 at 20:19
0

Changing org.hibernate.engine.internal.TwoPhaseLoad

final CacheKey cacheKey = session.generateCacheKey( id, 
persister.getIdentifierType(), persister.getRootEntityName() );    
--->    
final CacheKey cacheKey = session.generateCacheKey( id, 
persister.getIdentifierType(), persister.getEntityName() );

Fix the problem, but i am open for a beter solution

Nassim MOUALEK
  • 4,702
  • 4
  • 25
  • 44