javahibernatejunitehcachesecond-level-cache

How do I force a hit in my second-level cache in my JUnit test?


I’m using Hibernate 4.3.11.Final with the accompanying ehcache module. I want to verify in a JUnit (v 4.11) test that my second level cache is configured properly but I don’t know how to force such a situation. I have a simple method for retrieving an entity by its id, which is

public T findById(final Serializable id)
{
    T ret = null;
    if (id != null)
    {
        ret = (T) m_entityManager.find(persistentClass, id);
    }   // if
    return ret;
}

And then in n my JUnit test I have this

@Test
public void testSecondLevelCache()
{
    long hitCount = m_cache.getStatistics().getCacheHits();

    final String countryId = m_testProps.getProperty("test.country.id");
    m_countryDao.findById(countryId);
    m_countryDao.findById(countryId);

However the second call hits Hiberntae’s first-level cache and repeated calls to the DAO method will also hit Hibernate’s first level cache. How do I force a hit into the second level cache?

Edit: Below is how the transaction manager and other relevant sections are configured in my Spring application context ...

<cache:annotation-driven />

<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml"
p:shared="true" />

<util:map id="jpaPropertyMap">
    <entry key="hibernate.show_sql" value="true" />
    <entry key="hibernate.dialect" value="org.mainco.subco.core.jpa.SubcoMysql5Dialect" />
    <entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
    <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
    <entry key="hibernate.cache.use_second_level_cache" value="true" />
    <entry key="hibernate.cache.use_query_cache" value="false" />
    <entry key="hibernate.generate_statistics" value="true" />
    <entry key="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE" />
</util:map>

<bean id="sharedEntityManager"
    class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Solution

  • First, you need to remove the @Transactional annotation from the test or class level so that you control transactions manually.

    Second, you need to change the test to use two consecutive transactions with two EntityManager instances.

    @Test
    public void testSecondLevelCache() {
        long hitCount = m_cache.getStatistics().getCacheHits();       
        final String countryId = m_testProps.getProperty("test.country.id");
    
        transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {            
            m_countryDao.findById(countryId);
            return null;
        });
    
        transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {
            m_countryDao.findById(countryId);
            return null;
        });
    }