Spring-Boot - 激活休眠二级缓存

标签 spring jpa spring-boot ehcache

我正在尝试在使用 spring-boot-starter-data-jpa 的 Spring-Boot 应用程序上激活 Hibernate 2nd Level Cache。我使用 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 加载它们。之后,我试图通过调用以下代码来验证加载的 Employee 是否真的进入了缓存:
Assert.assertTrue(em.getEntityManagerFactory().getCache().contains(Employee.class, employeeId));

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

有任何想法吗?

编辑
我剥离了该项目并将其添加到公共(public) gitlab 存储库中,以便您重现它:https://gitlab.com/matrium00/reproduce-cache-issue

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

编辑2
以下是 em-factory 的工作 XML 配置示例没有 Spring Boot 。我知道我可以在我的配置类中手动创建必要的 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 测试方法和 @DataJpaTest 上的注释(也意味着 @Transactional)在你的测试课上。

因为只有一个事务,所以会有一个 session 。当您在同一个事务中访问同一个持久对象时,Hibernate 使用一级缓存( session 缓存)。要在二级缓存中取得成功,您应该有不同的 session (不同的事务)。

简单替换 @DataJpaTest@SpringBootTest并删除 @Transactional from test 方法使测试工作。

也可以看看:

  • This answer关于一级和二级缓存。
  • This tutorial关于二级缓存。
  • 关于Spring-Boot - 激活休眠二级缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46650475/

    相关文章:

    java - 限制 Spring Controller 同时处理少数请求

    java - (xml)cvc-complex-type.2.4.a : Invalid content was found starting with element 'init-param'

    java - Jpa多对多我怎样才能将数据插入2个表

    java - Spring Boot 客户端应用程序中未加载属性

    spring-boot - 在 Spring REST 文档中包含 "try out"表单

    java - 如果我只是添加一个新的子对象 java hibernate spring ,可以保存父对象吗?

    java - (JPQL) - 查询获取记录数最多的用户

    java - 在 Hibernate/JPA 中可选地使用级联

    java - Spring Boot 在测试时模拟其他休息客户端

    java - Spring 生成的 WSDL 公开了错误的协议(protocol)(HTTP 与 HTTPS)端点位置