Spring-启动 - 激活 Hibernate 二级缓存

Spring-Boot - Activating Hibernate 2nd Level Cache

我正在尝试在使用 spring-boot-starter-data-jpa 的 Spring-Boot 应用程序上激活 Hibernate 二级缓存。我使用 Ehcache 2 并在我的类路径中有 hibernate-ehcache

我使用了以下属性

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

我还像这样在 src/main/resources 中创建了 ehcache.xml(只是使用永不过期的缓存进行测试)

<ehcache updateCheck="false" monitoring="autodetect"
     dynamicConfig="true">

  <defaultCache
        maxElementsInMemory="100000"
        maxElementsOnDisk="10000000"
        eternal="true"
        overflowToDisk="false">
  </defaultCache>
</ehcache>

实体也用 @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 注释,在日志文件中我可以清楚地看到默认缓存用于实体,因此它似乎像往常一样识别注释并初始化缓存。

WARN .h.c.e.AbstractEhcacheRegionFactory : HHH020003: Could not find a specific ehcache configuration for cache named [at.test.demo.persistence.entity.Employee]; using defaults.

现在为了测试这个,我写了一个简单的测试,插入 3 名员工并使用通常的 JPA-Entitymanager 加载它们。在那之后,我试图通过调用这个来验证加载的员工是否真的进入了缓存:

Assert.assertTrue(em.getEntityManagerFactory().getCache().contains(Employee.class, employeeId));

但这总是失败。此外,SessionFactory-Statics 对所有内容都显示为零,这是不对的。

有什么想法吗?

编辑 我剥离了该项目并将其添加到 public gitlab 存储库供您重现:https://gitlab.com/matrium00/reproduce-cache-issue

由于这个问题,目前有一个单元测试失败了。

EDIT2 这是 em-factory 没有 Spring-Boot 的工作 XML 配置示例。我知道我可以在我的 Configuration-Class 中手动创建必要的 bean,但必须有更好的方法:

<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>

你的考试 @Transactional annotation on your test method and @DataJpaTest(这也意味着 @Transactional)class。

因为只有一个交易,所以会有一个会话。当您在同一个事务中访问同一个持久对象时,Hibernate 使用一级缓存(会话缓存)。要在二级缓存中命中,你应该有不同的会话(不同的事务)。

简单地将 @DataJpaTest 替换为 @SpringBootTest 并从测试方法中删除 @Transactional 即可进行测试。

另请参阅:

  • This answer关于一级缓存和二级缓存
  • This tutorial关于二级缓存