从休眠会话中删除对象

时间:2011-09-27 11:08:27

标签: hibernate exception lazy-initialization

我有hibernate pojo类A {B b;对于B类,lazy = true的其他一些属性} 当我得到对象A时,未加载B并且hibernate返回其代理。当我将此对象传递给另一个模块时,该模块遍历A中的每个对象,当它遇到B.getXXX时,它会抛出LazyInitialization异常。在这种特殊情况下,我不想加载B类,因为它不是必需的。有什么办法,当我在B上调用方法时,它返回null或将B的代理转换为实际对象B,以便模块不会抛出LazyInitialization错误。我不能改变B类getter,setter作为普通类,并且可以被许多其他类使用。

4 个答案:

答案 0 :(得分:1)

如果我理解你的问题,那么你正在检索一个与B有惰性关联的对象A.但是,这个关联没有被初始化,你发现其他模块正在抛出异常,因为B实际上是在使用。所以 需要某种方式。

你想要

  • null的调用中返回B(据我所知,这是不可能的,除非这些模块上有一些特定于应用程序的行为,只有您可以知道)或< / p>

  • 发生此类调用时初始化B。我会尽力帮你实现这个。

您获得LazyInitializationExceptions的原因是获取B(并且未初始化)的会话已经关闭,因此此时{{1}的实例根本没用。您可以在此处应用的一种解决方法是使用OSIV pattern,以便在所有请求范围内打开相同的Hibernate会话。这是一个会使用惰性B获取A的会话,会在需要时初始化B

您可以应用的另一个选项是在另一个会话中初始化B(仅当在另一个事务的上下文中发生这些异常时才有效,也就是说,打开另一个Hibernate会话,与获取的不同) B)。例如:

A

当然,您可以随时强制使用session.update(a.getB()); B初始化fetchMode.EAGER。但这将无条件地加载实例,即使它根本不会被使用。

此外,您可能会发现此问题的答案可能有用:hibernate: LazyInitializationException: could not initialize proxy

答案 1 :(得分:0)

实际上,你有一些选择。

1)使A-> B关系EAGER。

2)当您在休眠会话已经关闭时尝试启动代理时,您将获得LazyInitializationExceptions。所以他可能的解决方案是保持Session打开,直到所有的A,B,C ......等对象操作都没有完成。

3)如果你正在谈论WEB环境,那么在视图中有一种称为Open Session的模式。这使得Hibernate会话保持打开状态,直到您的HTTP请求处于活动状态。

我可以阅读更多相关信息here。我认为阅读它会很有用。

答案 2 :(得分:0)

会话关闭时,请勿将实体发送到其他模块。

如果这些其他模块在与会话相同的应用程序域中执行,请在调用模块时保持会话打开,并在返回时关闭它。

如果这些模块不在同一个AppDomain中,如果需要某种序列化来发送对象,或者如果它是异步调用的话,我会使用DTO。将实体暴露在服务器之外(我不知道这是否是这种情况)是一种不好的做法,原因有几个。 Ayende Rahien称之为Stripper Pattern

答案 3 :(得分:0)

感谢你的所有建议。 我的应用程序有分层架构。服务 - &GT;管理器 - &GT;道。 Hibernate会话在经理之后关闭。其他模块仅通过服务进行交互。打开hibernate会话直到请求完成不是我的选择。我也不想命中数据库,因为没有必要填充B的属性。我只想用真实对象替换hibernate代理,这样任何使用服务的人都不会遇到任何问题。我找到了一个实用工具 http://svn.rhq-project.org/repos/rhq/branches/HEIKO-EXP/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java 这正是我想要的。它检查对象并用真实对象替换hibernate代理。我需要在上面的实用程序中自定义以下内容 1.将org.rhq中的classname实例更改为我的包结构。 他们希望pojo中的身份字段名称是“id”。我将其更改为使用那些注释为javax.persistence.Id。

的属性

完成上述更改的基本测试,并且工作正常。我只需要使用各种场景测试整个应用程序,以便它可以在所有场景中运行。