Reputation: 2355
i am trying to activate Hibernate 2nd Level Cache on a Spring-Boot Application that uses spring-boot-starter-data-jpa. I use Ehcache 2 and have hibernate-ehcache in my classpath for that
I used the following properties
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.use_query_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
spring.jpa.properties.hibernate.generate_statistics=true
Also i created ehcache.xml in src/main/resources like this (just a test with a cache that never expires)
<ehcache updateCheck="false" monitoring="autodetect"
dynamicConfig="true">
<defaultCache
maxElementsInMemory="100000"
maxElementsOnDisk="10000000"
eternal="true"
overflowToDisk="false">
</defaultCache>
</ehcache>
Also the Entity is Annotated with @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
and in the logfile I can clearly see that the default cache is used for the Entity, so it seems to recognize the Annotation and initialize the cache as usual.
WARN .h.c.e.AbstractEhcacheRegionFactory : HHH020003: Could not find a specific ehcache configuration for cache named [at.test.demo.persistence.entity.Employee]; using defaults.
Now to test this I wrote a simple Test that inserts 3 Employees and loads them using usual JPA-Entitymanager. After that I am trying to verify that the loaded Employee actually really got into the Cache, by calling this:
Assert.assertTrue(em.getEntityManagerFactory().getCache().contains(Employee.class, employeeId));
But that always fails. Also the SessionFactory-Staticstics shows zeros for everything, that cant be right.
Any ideas?
EDIT I stripped down the project and added it to public gitlab repo for you to reproduce it: https://gitlab.com/matrium00/reproduce-cache-issue
There is a single unit test for this that fails right now because of the problem.
EDIT2 Here is an example of a working XML configuration of em-factory without Spring-Boot. I know I could create the necessary beans in my Configuration-Class manually, but there has to be a better way:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
autowire="byName" depends-on="flyway">
<property name="packagesToScan" value="at.my.package.demo.persistence.entity"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.default_schema">${jdbc.schema}</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
</bean>
Upvotes: 4
Views: 5607
Reputation: 2686
You have the @Transactional
annotation on your test method and @DataJpaTest
(which means @Transactional
too) on your test class.
As there is a single transaction, there will be a single session. When you are accessing the same persistent object inside of the same transaction, Hibernate uses first level cache (session cache). To take a hit in the second level cache, you should have different sessions (different transactions).
Simple replace of @DataJpaTest
with @SpringBootTest
and remove of @Transactional
from test method makes test to work.
See also:
Upvotes: 3