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关于二级缓存
我正在尝试在使用 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关于二级缓存