如何在Hibernate中从session.load(E.class, id)获取/初始化/取消代理数据?
解决Hibernate代理对象序列化时出现
hibernateLazyInitializer的问题 首先咱们理清问题根源:你用session.load()获取的是Hibernate代理对象,哪怕调用了Hibernate.initialize()初始化了实体数据,这个代理对象本身依然会携带hibernateLazyInitializer这个Hibernate内部属性。当Session关闭后,JSON序列化库(比如Jackson)尝试序列化这个属性时,就会因为它是Hibernate内部不可序列化的对象而报错。而且你代码里还有个小疏漏——最后返回的还是原代理对象el,而非unproxy后的el2,这导致unproxy操作完全没起作用。
下面给你几个可行的解决方案:
方案1:用session.get()替代session.load()
session.get()会直接返回实体对象(如果数据库中存在对应记录),不会生成代理对象,从根源上避免了hibernateLazyInitializer的问题。修改后的代码如下:
try (Session session = sessionFactory.openSession()) { session.beginTransaction(); final Employee el = session.get(E.class, id); // 直接获取实体实例,无代理 session.getTransaction().commit(); return el; }
方案2:正确使用Hibernate.unproxy()并返回unproxy后的对象
你之前的代码里,unproxy得到了真实实体el2,但最后返回的还是原代理el,等于白做了解除代理的操作。修改后要返回unproxy后的实体:
try (Session session = sessionFactory.openSession()) { session.beginTransaction(); final Employee el = session.load(E.class, id); Hibernate.initialize(el); // 初始化代理中的实体数据 Employee el2 = Hibernate.unproxy(el, E.class); // 解除代理,得到真实实体 session.getTransaction().commit(); return el2; // 返回真实实体,而非代理 }
方案3:配置JSON序列化工具忽略Hibernate内部属性
如果你的项目用Jackson作为JSON序列化库,可以引入Hibernate专属模块,它会自动处理Hibernate代理对象,忽略内部的hibernateLazyInitializer属性,还能按需初始化懒加载数据。示例配置:
ObjectMapper objectMapper = new ObjectMapper(); // 根据你的Hibernate版本选择对应模块,这里以Hibernate5为例 objectMapper.registerModule(new Hibernate5Module()); // 之后用这个objectMapper来序列化你的实体对象
内容的提问来源于stack exchange,提问作者Aliaksandr Shpak
相关产品推荐
相关产品推荐

