Redis二级缓存+Hibernate出现LazyInitializationException:无Session无法初始化代理
针对懒加载异常的优化解决方案
1. 缓存前主动初始化关联对象
在将A存入Redis前,在Hibernate Session活跃的上下文(比如@Transactional方法内),手动触发关联对象的懒加载,确保存入缓存的是完整实体而非代理:
A a = aDao.getById(aId); // 初始化B和C if (a.getB() != null) { Hibernate.initialize(a.getB()); Hibernate.initialize(a.getB().getC()); } // 存入Redis redisTemplate.opsForValue().set("cache:a:" + aId, a);
从Redis取出后,直接访问关联对象不会触发懒加载,避免异常。
2. 按需调整Fetch策略
如果业务场景中大部分访问A都需要用到B和C,可以修改关联的FetchType为EAGER,让Hibernate在查询A时直接加载关联对象:
@ManyToOne(targetEntity = InternalOrganizationImpl.class, fetch = FetchType.EAGER) @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE }) @JoinColumn(name = "bid") private B b;
注意:此方案会增加单次查询的数据库开销,仅适合关联对象高频访问的场景,同时要同步调整B类中C字段的Fetch策略或提前初始化。
3. 自定义Redis序列化逻辑
默认序列化可能仅保存Hibernate代理的标识,需自定义序列化器,在序列化时自动加载懒加载关联。以Jackson为例,配置Hibernate专属模块处理代理:
// 适配Hibernate 4的Jackson模块 Hibernate4Module hibernateModule = new Hibernate4Module(); // 强制序列化时加载懒加载对象 hibernateModule.enable(Hibernate4Module.Feature.FORCE_LAZY_LOADING); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(hibernateModule); // 配置RedisTemplate使用自定义ObjectMapper Jackson2JsonRedisSerializer<A> serializer = new Jackson2JsonRedisSerializer<>(A.class); serializer.setObjectMapper(objectMapper); redisTemplate.setValueSerializer(serializer);
序列化后存入Redis的是完整实体数据,取出后可直接访问关联对象。
4. 确保缓存读取逻辑在事务上下文内
@Transactional无效可能是因为读取Redis的代码不在事务范围内。将读取Redis和关联对象访问逻辑放在同一个@Transactional方法中,保证Hibernate Session活跃:
@Transactional public void handleA(Long aId) { A a = redisTemplate.opsForValue().get("cache:a:" + aId); // 此时Session处于活跃状态,可正常初始化代理 C targetC = a.getB().getC(); // 后续业务处理 }
需确认Spring事务配置正确(已开启@EnableTransactionManagement,事务管理器绑定Hibernate SessionFactory)。
内容的提问来源于stack exchange,提问作者Rookie lx
相关产品推荐
相关产品推荐

