Hibernate懒初始化失效 workaround:序列化克隆时关联列表未加载问题
问题1:现象产生的原因
你的猜测基本正确,该现象是JIT激进优化 + ORM懒加载机制共同导致的:
- 你从数据库查询得到的Product对象中,someList属性是ORM框架生成的懒加载代理对象,只有实际访问代理对象的内容时,才会触发数据库查询完成属性初始化。
- 直接编写
prod.getSomeList();时,由于方法返回值没有被任何逻辑使用,JIT优化阶段会判定该调用没有可观测的副作用,直接将这行代码消除,因此没有触发懒加载初始化。 - 调试模式下JIT会关闭大部分激进优化,代码会按原始书写逻辑执行,因此手动调用get方法会正常触发初始化。
- 序列化未初始化的懒加载代理时,只会序列化代理的空壳,反序列化后得到的对象处于无效状态,调用getSomeList自然会抛出异常。
问题2:更优雅的初始化替代方案
不需要通过打印触发初始化,可选择以下几种方案:
方案1:主动调用集合方法触发初始化(成本最低)
只需要调用返回集合的size()方法即可触发懒加载,你可以封装成通用工具方法:
public class LazyInitUtils { public static void init(Collection<?> collection) { if (collection != null) { // 调用size()会强制触发懒加载代理的加载逻辑 collection.size(); } } }
使用方式:
Product prod = getProdFromDB(); LazyInitUtils.init(prod.getSomeList()); Product copiedProd = clone(prod); // 正常访问不会报错 copiedProd.getSomeList();
方案2:改造克隆方法自动处理懒加载
如果需要处理多个懒加载字段,可以通过反射遍历待克隆对象的所有字段,自动识别集合类型的懒加载代理并触发初始化,不需要业务代码手动处理每个字段。
方案3:改用映射工具实现深拷贝
如果业务允许,也可以改用MapStruct、Orika等对象映射工具实现深拷贝,这类工具可以配置自动触发懒加载属性的初始化,不需要额外编写初始化逻辑。
注意:你当前使用的序列化克隆方案,需要保证Product类及其所有关联属性的类都实现
Serializable接口,否则序列化过程会抛出异常。
内容的提问来源于stack exchange,提问作者waynewing
相关产品推荐
相关产品推荐

