Spring Data JPA中Hibernate查询缓存失效问题求助
问题现象
使用Spring Boot Starter Data JPA 2.6.4配置Hibernate二级缓存和查询缓存后,每次调用getByEventCode方法仍会执行SQL语句,缓存未生效。
核心问题与修复方案
1. 实体类扫描范围缺失
在NotificationDataSourceConfig的notificationEntityManagerFactory方法中,setPackagesToScan仅指定了MessageEntity的包,未包含Events实体所在的包,导致Hibernate无法识别Events类上的@Cacheable等缓存注解。
修复代码:
@Primary @Bean(name="notificationEntityManagerFactory") public LocalContainerEntityManagerFactoryBean notificationEntityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(getDataSource()); // 同时扫描所有通知模块实体类所在包 em.setPackagesToScan( "com.dhre.realconnect.notificationService.notificationEntities" ); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(additionalProperties()); return em; }
2. 手动EntityManagerFactory未加载缓存配置
自定义LocalContainerEntityManagerFactoryBean时,additionalProperties方法仅设置了基础Hibernate属性,没有加载application.properties中配置的缓存相关属性,导致Hibernate缓存配置未生效。
修复代码:
// 新增缓存配置属性注入 @Value("${spring.jpa.properties.hibernate.cache.region.factory_class}") private String cacheRegionFactory; @Value("${spring.jpa.properties.javax.persistence.sharedCache.mode}") private String sharedCacheMode; @Value("${spring.jpa.properties.hibernate.cache.use_second_level_cache}") private String useSecondLevelCache; @Value("${spring.jpa.properties.hibernate.cache.use_query_cache}") private String useQueryCache; Properties additionalProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.show_sql", hibernateShowSql); // 修正拼写错误:原hibernate.properties.dialect改为hibernate.dialect properties.setProperty("hibernate.dialect", hibernateDialect); // 添加缓存配置 properties.setProperty("hibernate.cache.region.factory_class", cacheRegionFactory); properties.setProperty("javax.persistence.sharedCache.mode", sharedCacheMode); properties.setProperty("hibernate.cache.use_second_level_cache", useSecondLevelCache); properties.setProperty("hibernate.cache.use_query_cache", useQueryCache); return properties; }
3. 原生SQL查询缓存的局限性
Hibernate对原生SQL查询的查询缓存支持有限,即使添加了@QueryHint(CACHEABLE=true),也可能无法正常触发缓存。建议改用JPQL查询,更兼容Hibernate的缓存机制。
修复Repository代码:
@Repository public interface EventRepository extends JpaRepository<Events, Integer>{ // 替换原生SQL为JPQL查询 @Query("SELECT e FROM Events e WHERE e.eventCode = :eventCode") @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) Optional<Events> getByEventCode(String eventCode); }
4. 依赖版本兼容性问题
Spring Boot 2.6.4默认依赖的Hibernate版本是5.6.7.Final,当前手动指定的hibernate-ehcache版本为5.6.5.Final,版本不一致可能导致缓存组件兼容性问题。建议移除手动版本号,由Spring Boot依赖管理自动匹配。
修复pom.xml:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <!-- 移除手动指定的版本,依赖Spring Boot自动管理 --> </dependency>
验证步骤
- 启动应用后,第一次调用
getByEventCode,控制台会打印SQL语句。 - 第二次调用相同参数的
getByEventCode,控制台不再打印SQL,说明查询缓存生效。 - 可开启缓存日志进一步验证,在
application.properties中添加:
日志中出现logging.level.org.hibernate.cache=DEBUGCache hit: region=...字样,证明缓存命中。
内容的提问来源于stack exchange,提问作者SATWIK BADANI

