Hazelcast+Hibernate+Spring Boot集成遇懒加载无Session错误求助
解决Hazelcast 5.3 + Hibernate 5.6 + Spring Boot 2.7 集成时@Cacheable方法的LazyInitializationException问题
问题根源
你的问题出在自定义CacheManager破坏了Spring Boot默认的缓存与Hibernate会话管理的整合逻辑。手动创建HazelcastCacheManager后,Spring Boot自动配置中针对Hibernate实体缓存的会话绑定机制被覆盖,导致从Hazelcast缓存取出的Hibernate代理实体(带懒加载关联)无法获取有效Session初始化关联数据,最终抛出LazyInitializationException。
解决方案
方案1:移除自定义CacheManager,依赖Spring Boot自动配置
Spring Boot会自动检测Config或HazelcastInstance Bean,并创建适配Hibernate上下文的HazelcastCacheManager,无需手动定义。修改配置类如下:
@Configuration public class HazelCastConfiguration { @Bean public Config hazelcastConfig() { Config config = new Config(); config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(true); config.setClassLoader(Thread.currentThread().getContextClassLoader()); final UserCodeDeploymentConfig distCLConfig = config.getUserCodeDeploymentConfig(); distCLConfig.setEnabled(true) .setClassCacheMode(UserCodeDeploymentConfig.ClassCacheMode.ETERNAL) .setProviderMode(UserCodeDeploymentConfig.ProviderMode.LOCAL_CLASSES_ONLY); // 添加业务用到的缓存配置,包括@Cacheable中指定的缓存名称 config.addMapConfig(rajouterConfig("produits",5000,0)); config.addMapConfig(rajouterConfig("CACHE_MANAGER", 5000, 0)); return config; } private MapConfig rajouterConfig(String nomCache, int taille, int tempsDeVie){ return new MapConfig() .setName(nomCache) .setTimeToLiveSeconds(tempsDeVie) .setEvictionConfig(new EvictionConfig() .setSize(taille) .setMaxSizePolicy(MaxSizePolicy.PER_NODE) .setEvictionPolicy(EvictionPolicy.LRU)); } // 可选:如需自定义HazelcastInstance创建逻辑则保留,否则Spring Boot会自动生成 @Bean public HazelcastInstance hazelcastInstance() { return Hazelcast.newHazelcastInstance(hazelcastConfig()); } // 移除自定义的cacheManager Bean! }
方案2:若必须自定义CacheManager,配置Hazelcast序列化策略
如果一定要手动创建HazelcastCacheManager,需配置能处理Hibernate代理的序列化器:
- 引入
hazelcast-hibernate5依赖:
<dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-hibernate5</artifactId> <version>5.3.0</version> </dependency>
- 在
hazelcastConfig()方法中添加序列化配置:
config.getSerializationConfig() .addSerializerConfig(new SerializerConfig() .setTypeClass(org.hibernate.proxy.HibernateProxy.class) .setClass(com.hazelcast.hibernate.serialization.Hibernate4CacheSerializer.class));
方案3:避免缓存Hibernate代理实体
直接缓存DTO而非Hibernate实体,或在方法返回前初始化所有懒加载关联:
- 在
recupererParModele方法中,调用数据库查询后,用Hibernate.initialize(entity.getLazyAssociation())手动初始化懒加载属性 - 将查询结果转换为DTO对象,缓存DTO而非实体类,彻底规避Hibernate代理问题
内容的提问来源于stack exchange,提问作者user2976252
相关产品推荐
相关产品推荐

