javahibernatejpaehcachehibernate-cache

Hibernate EhCache not used?


This is a part of my persistence.xml

<property name="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE" />

<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.show_sql" value="true" />            
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.generate_statistics" value="true"/>

<!-- set cache provider -->
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />

<!-- enable second level cache and query cache -->
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />

The ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" 
    updateCheck="true"
    monitoring="autodetect" 
    dynamicConfig="false">

    <diskStore path="java.io.tmpdir/ehcache" />

    <defaultCache 
        maxEntriesLocalHeap="10000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        diskSpoolBufferSizeMB="30"
        maxEntriesLocalDisk="10000000" 
        diskExpiryThreadIntervalSeconds="120"
        statistics="true">
        <persistence strategy="localTempSwap" />
    </defaultCache>

</ehcache>

Finally, the main method (I want to be JPA compliant)

void main()
{
    EntityManagerFactory emf = null;        
    EntityManager em = null; 

    try {

        emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);

        em = emf.createEntityManager();

        Session session = em.unwrap( Session.class );

        Customer find;

        Transaction transaction = session.getTransaction();

        transaction.begin();

        CustomerPk pk = new CustomerPk();
        pk.setUidCliente("fabrizio.sttrd0l7c0@gmail.com");

        find = em.find(Customer.class, pk);

        find = em.find(Customer.class, pk);

        transaction.commit();

        logger.info("END");

    } catch (Exception e) {
        logger.error(e.getMessage());
    } finally {
        Optional.ofNullable(em).ifPresent(x -> { x.close(); });
        Optional.ofNullable(emf).ifPresent(x -> { x.close(); });            
    }
}

Now I'd expect that 2nd level cache should be 'hitted' on the second find call, but it's not, because the logged statistics print the following:

20786 nanoseconds spent acquiring 1 JDBC connections;
20057 nanoseconds spent releasing 1 JDBC connections;
169837247 nanoseconds spent preparing 1 JDBC statements;
322972879 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
4190446 nanoseconds spent performing 1 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
1239520 nanoseconds spent performing 1 L2C misses;
6351857 nanoseconds spent executing 1 flushes (flushing a total of 1 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

As you can see, 0 L2C hits.

What's wrong with this?


Solution

  • You're using the same EntityManager for the both fetch operation so it doesn't need to reach l2 cache as l1 already matches.

    L1 cache is the entity manager state and is so bound to EM lifecycle. L2 cache is at the entityManagerFactory level and is so shared between all EM created by the same factory.