Sql-Hibernate中如何正确的使用集合

Hibernate(实际上是JPA)具有集合映射:@OneToMany,@ManyToMany,@ElementCollection。所有这些都默认为懒惰。这意味着集合是List或Set接口的特定实现,它们持有对持久会话的引用,并且仅当访问集合时才从数据库加载值。这可以节省不必要的数据库查询,如果你只是偶尔使用集合。

但是,这有一个问题。这个问题通过我观察到的第二个最常见的异常(在NullPointerException之后) – LazyInitializationException异常表现出来。问题在于会话通常对您的服务层开放,并在您将实体返回到视图图层时立即关闭。当你尝试在视图中迭代未初始化的集合(例如jsp)时,集合抛出LazyInitializationException,因为它们持有引用的会话已经关闭,并且它们无法获取这些项目。

这是如何解决的?所谓的OpenSessionInView / OpenEntityManagerInView“模式”。简而言之:你制作了一个过滤器,当请求开始时打开会话并在视图被渲染后(而不是在服务层完成之后)关闭它。有些人称这是一种反模式,因为它将持久性处理泄露到视图层中,并使设置复杂化。我不会说这很糟糕:通常它可以解决问题而不会引入其他问题。但在我参与的所有最近的项目中,我们没有使用OpenSessionInView,而且它工作正常。

它工作正常,因为我们没有使用懒惰的集合。但是,你会正确地指出,你会当您加载一个单一的实体获取“整个世界”。那么,不。有两种类型的* ToMany映射:

  • 值类型映射,其中逻辑上集合不包含十几个元素。在大多数情况下,@ElementCollection和@ * ToMany都带有“类别”或“价格”等项目,它们只是更复杂的值对象,但它们本身并不包含任何其他映射。这些类型的集合的另一个常见特征是它们通常与其拥有的实体一起显示在UI中。例如,很可能您想显示文章的类别。对于这种类型的集合EAGER是更好的选择。无论如何,你必须获取它们,为什么不让hibernate(或任何jpa实现)想到一些聪明的连接?正如我所说 – 集合在逻辑上不会超过一两个,所以提取它们不会成为性能问题。而且,从逻辑上讲,他们不会用它们获取大对象图。
  • 映射到大型核心实体。这可以是“用户所做的所有订单”或“组织的所有用户”,“供应商的所有项目”等等。您当然不想急于获取它们。因为如果你为一个组织提取2000个用户,而每个组织有1000个订单,并且一个订单平均有3个项目,而这些项目又有一个所有购买它的人的集合..你将最终获得整个数据库在记忆中。显然你需要懒惰的集合,对吧?那么,不。在这种情况下,你根本不应该使用集合映射。这些类型的关系在99%的情况下显示在UI中的分页列表中。或在搜索结果中。它们绝不会(也不应该)全部显示在一个屏幕上(或者,如果您的应用程序提供了类似REST API的API,则很少在一次API调用中返回)。你必须为它们查询,并使用query.setMaxResults和query.setFirstResult()(或限制它们的一些限制条件)。此外,映射集合意味着有人会尝试在某个时刻使用它们,这可能会失败。如果对象被序列化(xml,json等),则会获取集合内容。你几乎肯定不希望发生的事情。(这里有一个草案的概念:JPA可以有一个PagedList集合,允许分页延迟获取,因此不需要查询)你几乎肯定不希望发生的事情。(这里有一个草案的概念:JPA可以有一个PagedList集合,允许分页延迟获取,因此不需要查询)你几乎肯定不希望发生的事情。(这里有一个草案的概念:JPA可以有一个PagedList集合,允许分页延迟获取,因此不需要查询)

那么我刚刚说了什么 – 你不应该使用懒惰的集合。使用渴望的集合进行非常简单的浅层映射,并为较大的映射使用分页查询。

那么,不完全是。懒惰的集合在那里,他们有应用程序,虽然它是相当有限的。或者至少它们比使用的方式更不适用。以下是我发现它适用的一个示例场景。在我的侧面项目我有一个Message实体,它拥有一个Picture实体的集合。用户上传图片时,会将其存储在该集合中。一条消息可以有不超过10张图片,所以收藏可能非常渴望。但是,消息是最常用的实体 – 它在每个请求上都被虚拟地获取。但是只有一些消息会有图片(您的流中有多少推文有图片上传?)。所以我不希望休眠查询只是为了找出给定的消息没有图片。因此,我只在图片数大于0的情况下,将图片数量存储在单独的字段中,使图片集懒散,并手动Hibernate.initialize(..)。

所以有些情况下,当实体具有属于上述第一类的可选集合(“小,浅集合”)时。因此,如果它很小,很浅并且可选(比如在少于20%的情况下使用),那么您应该使用Lazy来节省不必要的查询。

原创于 【模棱博客】