JPA Hibernate Lazy加载集合

时间:2016-08-15 12:48:55

标签: java spring hibernate jpa

我知道这已经反复讨论了(我在这个问题上有几个我自己的实现),也许这就是我要问的原因的一部分:没有明确的答案(经过几个小时的搜索)而且我觉得这是捕获22。

我的设置是Spring Boot 1.3.6,已经结婚了#34;到Hibernate 4.3.11。我正在使用Spring Data JPA。

我有一个实体,其中包含多个子实体集合@OneToMany@ManyToMany。这就是模特 - 它不适合我爱或恨。

然后我有一个普通的CRUD UI,其中包含一个主实体表和一个编辑器,用户可以在其中为子实体选择选项并保存主实体。

用Vaadin完成UI,并且涉及Web套接字。所以 - 不是正常的Http交换。

通过正常设置,我得到了#34;正常"来自Hibernate的LazyInitializationException。因为,一旦实体被加载到表格屏幕中,会话就会被关闭,因此,当在编辑器屏幕中调用集合时,我要么完全重新加载实体,哪种类型会杀死使用ORM的所有mojo,或者我尝试别的东西:

  • 使收藏品成为EAGER(并随身携带它们,更不用说n + 1问题了,尽管@Fetch(FetchMode=JOIN)本来不应该在那里发生的事情)
  • spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true添加到我的启动配置中,这与第一个选项基本相同,变为默认值。不,谢谢。
  • 在检索父实体之后(即在同一会话中)对集合使用Hibernate.initialize,这类似于程序化EAGER检索 - 但它与Hibernate高度耦合,并且它没有'我省了额外的查询(n + 1)。
  • 使用" fetch join"检索数据在我的JPQL查询中 - 除了这可能导致结果集升级到数千行(然后在内存中聚合),更不用说A)它需要JPQL用于其他简单的查询,在Spring Data和B中使用简单的接口名称实现)如果你想要分页,你还需要编写countingQuery(没有连接获取),否则你会得到一个漂亮,清晰且易于调试的org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list。另外,如果你忘了"要删除fetchType@OneToMany注释中的@ManyToMany选项,您会获得另一个令人毛骨悚然的例外:org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
  • 按照开放视图模式(或者更确切地说是反模式)创建一个过滤器,它会为同一个中的所有请求检索相同的EntityManager,好吧,某些东西 - 而不是Http Session,因为我们使用Web套接字(或者其他任何东西,Hibernate不应该是Web ORM);不是Vaadin会话,因为我可能选择拥有多个servlet,或者分发整个应用程序;或停止使用Vaadin;不是本地的线程,因为我可能选择在不同的线程池中执行操作,而不是从本地线程继承:再次,这不是Hibernate的关注。

最后,切换到EclipseLink,它具有更明智的方法,只需在新的会话中请求子集合,似乎比Spring Boot通常提供的更多苦差事(有几个关于使用仪器代理运行应用程序的必要性仍在讨论中。

那么,最终,是否存在针对此问题的无黑客解决方案?

1 个答案:

答案 0 :(得分:1)

使用hibernate有两种主要策略。

  • 长期会话(保持db-session并行到http-session)
  • 短暂的会话(在conn-close之后抛出LazyInitializationException

LazyInitializationException向我们提供了您使用short-lived-session的提示。

要么使用长期会话并使用MVC视图中的实体。 您将实体中的所有值重新映射到非实体的新包装器。

我建议保留short-lived-session策略并将所有值重新映射到pojos以供查看。因为:db-structure很少是前端所需的信息结构。例如:

您有两个实体:

  • 用户
    • long UserId
    • 字符串名字
    • 字符串姓氏
  • 地址
    • long AddressId
    • String Street
    • String Zip
    • String City
    • long UserId

但是在视图中你有这个Dataobject(DTO):

  • 类用户
    • 字符串名字
    • 字符串姓氏
    • String Street
    • String Zip
    • String City

你知道,豆子是不同的,你不会在conn-close之后得到LazyInitializationException