org.hibernate.lazyinitialization 异常

Posted

技术标签:

【中文标题】org.hibernate.lazyinitialization 异常【英文标题】:org.hibernate.lazyinitialization exception 【发布时间】:2012-01-07 17:36:30 【问题描述】:

org.hibernate.LazyInitializationException: 延迟初始化角色集合失败:pojo.Person.address,没有会话或会话已关闭。

我遇到了这个异常,我正在使用 Spring 3.0 和 Hibernate 3.6。

【问题讨论】:

不幸的是,除非您准备一个小而简洁的示例来重现相同的错误并将其发布在此处,否则没有人可以帮助您。 默认情况下额外休眠以惰性方式加载集合意味着它不会加载集合并返回代理对象,您可能会在会话关闭后尝试访问集合。 【参考方案1】:

我看到此问题是因为我未能使用 @Transactional 注释服务中的方法。当调用另一个方法时(即使在同一个类中),Hibernate 似乎会关闭会话,除非调用者被适当地注释。

【讨论】:

【参考方案2】:

看起来你有一个名为 Person 的实体,它有一个延迟加载的地址映射集合?您已经加载了 Person 并且加载它的会话现在已经关闭。

会话关闭后,您尝试访问该地址集合,Hibernate 尝试加载它们。但是,如果原始会话不再可用,则这是不可能的。

为了访问地址属性,您有几个选项:

    使用 OpenSessionInView 模式确保 Hibernate 会话在请求/响应周期期间保持打开状态(由于您已标记 Spring MVC,我假设这是基于 Web 的操作)。这实质上将您的 Hibernate 会话范围限定为 HTTP 请求。

    确保在会话关闭(事务提交)之前加载所有必需的属性。您可以使用

    Hibernate.initialize(person.address)

或者通过编写使用左连接提取的 HQL。这可能是这样的:

createQuery("from Person as person left join fetch person.address")

这将仅覆盖此查询的任何延迟加载配置,并确保初始化任何集合。

【讨论】:

Alex,你不觉得这相当于 FetchType.EAGER 吗?这会降低性能。 但是你需要急切地获取这个,否则你会得到 LazyInitializationExceptions!这正是你所看到的!您将需要加载此集合,因此您最好在关闭会话之前执行此操作。使用左连接提取的好处在于您可以在映射中指定 FetchType.Lazy。当您知道不需要访问地址集合时,大多数情况下都会使用此选项。但是当你知道你需要访问集合时,你可以覆盖惰性映射!你明白了吗? 您看到的异常表明您已尝试访问地址属性。因此,您将不得不在某个时候加载它。它不会在没有性能开销的情况下神奇地出现在您的会话中。再好不过了。【参考方案3】:

很可能,您没有设置事务管理。也就是说,Spring 使用默认的事务范围,即每个HibernateTemplate 调用的事务,并在从HibernateTemplate 返回后立即关闭会话。

你可以做以下三件事之一:

    设置交易, 切换到显式会话处理, 使用 Criteria API 或 fetch join 来预取您需要的详细信息。

【讨论】:

感谢 alf 的快速回复。你能解释第三种选择吗?即使用标准 api 或 fetch join。实际上,我有一个包含带有 hbm.xml 的 pojos 的现有项目,它将被转换为带有注释的 pojos。 请不要偷懒。 docs.jboss.org/hibernate/core/3.3/reference/en/html/… 和 community.jboss.org/wiki/AShortPrimerOnFetchingStrategies 会给你一个开始。

以上是关于org.hibernate.lazyinitialization 异常的主要内容,如果未能解决你的问题,请参考以下文章