Hibernate 抛出 MultipleBagFetchException - 无法同时获取多个包

发布于 2024-10-05 10:14:49 字数 1812 浏览 12 评论 0原文

Hibernate 在 SessionFactory 创建期间抛出此异常:

org.hibernate.loader.MultipleBagFetchException:无法同时获取多个包

这是我的测试用例:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 // @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
 private List<Child> children;

}

Child.java

@Entity
public Child {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private Parent parent;

}

这个问题怎么样?我能做些什么?


编辑

好的,我遇到的问题是另一个“父”实体在我的父级内部,我的真实行为是这样的:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private AnotherParent anotherParent;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<Child> children;

}

AnotherParent.java

@Entity
public AnotherParent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<AnotherChild> anotherChildren;

}

Hibernate不喜欢两个带有FetchType.EAGER的集合,但这似乎是一个错误,我没有做不寻常的事情......

删除FetchType.EAGER来自 ParentAnotherParent 解决了问题,但我需要它,所以真正的解决方案是使用 @LazyCollection(LazyCollectionOption.FALSE) 而不是 < code>FetchType (感谢 Bozho 提供解决方案)。

Hibernate throws this exception during SessionFactory creation:

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

This is my test case:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 // @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
 private List<Child> children;

}

Child.java

@Entity
public Child {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private Parent parent;

}

How about this problem? What can I do?


EDIT

OK, the problem I have is that another "parent" entity is inside my parent, my real behavior is this:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private AnotherParent anotherParent;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<Child> children;

}

AnotherParent.java

@Entity
public AnotherParent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<AnotherChild> anotherChildren;

}

Hibernate doesn't like two collections with FetchType.EAGER, but this seems to be a bug, I'm not doing unusual things...

Removing FetchType.EAGER from Parent or AnotherParent solves the problem, but I need it, so real solution is to use @LazyCollection(LazyCollectionOption.FALSE) instead of FetchType (thanks to Bozho for the solution).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

遥远的她 2024-10-12 10:14:49

我认为较新版本的 hibernate(支持 JPA 2.0)应该可以处理这个问题。但除此之外,您可以通过使用以下方式注释集合字段来解决此问题:

@LazyCollection(LazyCollectionOption.FALSE)

请记住从 @*ToMany 注释中删除 fetchType 属性。

但请注意,在大多数情况下,SetList 更合适,因此除非您确实需要 List - 请使用对于Set

请谨慎使用

请记住,使用Set不会消除底层笛卡尔积,如< a href="https://stackoverflow.com/a/51055523/1657465">Vlad Mihalcea 在他的回答中,被称为“最糟糕的解决方案”

I think a newer version of hibernate (supporting JPA 2.0) should handle this. But otherwise you can work it around by annotating the collection fields with:

@LazyCollection(LazyCollectionOption.FALSE)

Remember to remove the fetchType attribute from the @*ToMany annotation.

But note that in most cases a Set<Child> is more appropriate than List<Child>, so unless you really need a List - go for Set

Use with caution

Remember that using a Set won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer, featured as "The worst solution"!

笑着哭最痛 2024-10-12 10:14:49

只需从 List 类型更改为 Set 类型即可。

谨慎使用

不建议使用此解决方案,因为它不会消除底层笛卡尔积,如 Vlad Mihalcea 在他的回答中,被列为“最糟糕的解决方案”

Simply change from List type to Set type.

Use with caution

This solution is not recommended as it won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer, featured as "The worst solution"!

夏见 2024-10-12 10:14:49

考虑到我们有以下实体:

在此处输入图像描述

并且,您想要获取一些父 Post 实体以及所有 commentstag集合。

如果您使用多个 JOIN FETCH 指令:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    left join fetch p.tags
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();

Hibernate 将抛出臭名昭著的错误:

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags [
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.comments,
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.tags
]

Hibernate 不允许获取多个包,因为这会生成笛卡尔积。

最糟糕的“解决方案”

现在,您会发现很多答案、博客文章、视频或其他资源告诉您在集合中使用 Set 而不是 List

这是个糟糕的建议。不要这样做!

使用 Sets 而不是 Lists 将使 MultipleBagFetchException 消失,但笛卡尔积仍将是在那里,这实际上更糟糕,因为在应用此“修复”很久之后您就会发现性能问题。

正确的 Hibernate 6 解决方案

如果您使用 Hibernate 6,那么您可以像这样解决此问题:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();

posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.tags t
    where p in :posts 
    """, Post.class)
.setParameter("posts", posts)
.getResultList();

只要您在每个查询中使用 JOIN FETCH 最多获取一个集合,就可以了。

通过使用多个查询,您将避免使用笛卡尔积,因为任何其他集合,但第一个查询是使用辅助查询获取的。

正确的 Hibernate 5 解决方案

您可以执行以下技巧:

List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.tags t
    where p in :posts 
    """, Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

在第一个 JPQL 查询中,distinct 不会转到 SQL 语句。这就是我们将 PASS_DISTINCT_THROUGH JPA 查询提示设置为 false 的原因。

DISTINCT 在 JPQL 中有两个含义,在这里,我们需要它在 Java 端(而不是 SQL 端)对 getResultList 返回的 Java 对象引用进行重复数据删除。

通过使用多个查询,您将避免使用笛卡尔积,因为任何其他集合,但第一个查询是使用辅助查询获取的。

您还可以做更多事情

如果您在映射 @OneToMany@ManyToMany 关联时使用 FetchType.EAGER 策略,那么您可以很容易以 MultipleBagFetchException 结束。

您最好从 FetchType.EAGER 切换到 Fetchype.LAZY,因为急切获取是一个糟糕的想法,可能会导致严重的应用程序性能问题。

结论

避免 FetchType.EAGER 并且不要从 List 切换到 Set 仅仅因为这样做会让 Hibernate 隐藏 MultipleBagFetchException在地毯下。一次只获取一个集合,就可以了。

只要您使用与要初始化的集合相同数量的查询来执行此操作,就可以了。只是不要在循环中初始化集合,因为这会触发 N+1 查询问题,这也会影响性能。

Considering we have the following entities:

enter image description here

And, you want to fetch some parent Post entities along with all the comments and tags collections.

If you are using more than one JOIN FETCH directives:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    left join fetch p.tags
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();

Hibernate will throw the infamous:

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags [
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.comments,
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.tags
]

Hibernate doesn't allow fetching more than one bag because that would generate a Cartesian product.

The worst "solution"

Now, you will find lots of answers, blog posts, videos, or other resources telling you to use a Set instead of a List for your collections.

That's terrible advice. Don't do that!

Using Sets instead of Lists will make the MultipleBagFetchException go away, but the Cartesian Product will still be there, which is actually even worse, as you'll find out the performance issue long after you applied this "fix".

The proper Hibernate 6 solution

If you're using Hibernate 6, then you can fix this issue like this:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();

posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.tags t
    where p in :posts 
    """, Post.class)
.setParameter("posts", posts)
.getResultList();

As long as you fetch at most one collection using JOIN FETCH per query, you will be fine.

By using multiple queries, you will avoid the Cartesian Product since any other collection, but the first one is fetched using a secondary query.

The proper Hibernate 5 solution

You can do the following trick:

List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.tags t
    where p in :posts 
    """, Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

In the first JPQL query, distinct DOES NOT go to the SQL statement. That's why we set the PASS_DISTINCT_THROUGH JPA query hint to false.

DISTINCT has two meanings in JPQL, and here, we need it to deduplicate the Java object references returned by getResultList on the Java side, not the SQL side.

By using multiple queries, you will avoid the Cartesian Product since any other collection, but the first one is fetched using a secondary query.

There's more you could do

If you're using the FetchType.EAGER strategy at mapping time for @OneToMany or @ManyToMany associations, then you could easily end up with a MultipleBagFetchException.

You are better off switching from FetchType.EAGER to Fetchype.LAZY since eager fetching is a terrible idea that can lead to critical application performance issues.

Conclusion

Avoid FetchType.EAGER and don't switch from List to Set just because doing so will make Hibernate hide the MultipleBagFetchException under the carpet. Fetch just one collection at a time, and you'll be fine.

As long as you do it with the same number of queries as you have collections to initialize, you are fine. Just don't initialize the collections in a loop, as that will trigger N+1 query issues, which are also bad for performance.

回梦 2024-10-12 10:14:49

在代码中添加 Hibernate 特定的 @Fetch 注释:

@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;

这应该可以解决与 Hibernate bug HHH 相关的问题-1718

Add a Hibernate-specific @Fetch annotation to your code:

@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;

This should fix the issue, related to Hibernate bug HHH-1718

厌倦 2024-10-12 10:14:49

在尝试了这篇文章和其他文章中描述的每个选项之后,我得出的结论是修复如下。

在每个 XToMany 位置 @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
之后

@Fetch(value = FetchMode.SUBSELECT)

这对我有用

After trying with every single option describe in this posts and others, I came to the conclusion that the the fix is a follows.

In every XToMany place @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
and intermediately after

@Fetch(value = FetchMode.SUBSELECT)

This worked for me

优雅的叶子 2024-10-12 10:14:49

要修复此问题,只需将嵌套对象的 Set 替换为 List 即可。

@OneToMany
Set<Your_object> objectList;

并且不要忘记使用fetch=FetchType.EAGER,它会起作用的。

如果您只想坚持使用列表,Hibernate 中还有一个概念 CollectionId

谨慎使用

请记住,您不会消除底层笛卡尔积,如Vlad Mihalcea 在他的回答中,被称为“最糟糕的解决方案”

To fix it simply take Set in place of List for your nested object.

@OneToMany
Set<Your_object> objectList;

And don't forget to use fetch=FetchType.EAGER, It'll work.

There is one more concept CollectionId in Hibernate if you want to stick with list only.

Use with caution

Remember that you won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer, featured as "The worst solution"!

转身以后 2024-10-12 10:14:49

您可以在 JPA 中保留展位 EAGER 列表,并向其中至少一个添加 JPA 注释 @OrderColumn (显然带有要订购的字段的名称)。不需要特定的休眠注释。
但请记住,如果所选字段在 Children 中没有从 0 开始的值,则可能会在列表中创建空元素

 [...]
 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 @OrderColumn(name="orderIndex")
 private List<Child> children;
 [...]

,那么您应该添加 orderIndex 字段

you can keep booth EAGER lists in JPA and add to at least one of them the JPA annotation @OrderColumn (with obviously the name of a field to be ordered). No need of specific hibernate annotations.
But keep in mind it could create empty elements in the list if the chosen field does not have values starting from 0

 [...]
 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 @OrderColumn(name="orderIndex")
 private List<Child> children;
 [...]

in Children then you should add the orderIndex field

淡淡の花香 2024-10-12 10:14:49

当您的保存集合的对象过于复杂时,使用 EAGER fetchType 并不是一个好主意,最好使用 LAZY,当您确实需要加载集合时,请使用: Hibernate.initialize(parent.child)Hibernate.initialize(parent.child) 来获取数据。

When you have too complex objects with saveral collection could not be good idea to have all of them with EAGER fetchType, better use LAZY and when you really need to load the collections use: Hibernate.initialize(parent.child) to fetch the data.

很快妥协 2024-10-12 10:14:49

我们尝试使用 Set 而不是 List,这真是一场噩梦:当您添加两个新对象时,equals() 和 hashCode() 无法区分它们!因为他们没有身份证。

Eclipse 等典型工具会从数据库表生成此类代码:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

您还可以阅读 这篇文章 正确地解释了 JPA/Hibernate 是如何混乱的。读完这篇文章后,我想这是我一生中最后一次使用 ORM。

我也遇到过领域驱动设计人员,他们基本上说 ORM 是一件可怕的事情。

We tried Set instead of List and it is a nightmare: when you add two new objects, equals() and hashCode() fail to distinguish both of them ! Because they don't have any id.

typical tools like Eclipse generate that kind of code from Database tables:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

You may also read this article that explains properly how messed up JPA/Hibernate is. After reading this, I think this is the last time I use any ORM in my life.

I've also encounter Domain Driven Design guys that basically say ORM are a terrible thing.

天涯沦落人 2024-10-12 10:14:49

对我来说,问题在于嵌套的EAGER获取。

一种解决方案是将嵌套字段设置为 LAZY 并使用 Hibernate.initialize() 加载嵌套字段:

x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());

For me, the problem was having nested EAGER fetches.

One solution is to set the nested fields to LAZY and use Hibernate.initialize() to load the nested field(s):

x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());
昔日梦未散 2024-10-12 10:14:49

最后,当我使用 FetchType.EAGER 拥有多个集合时,就会发生这种情况,如下所示:

@ManyToMany(fetch = FetchType.EAGER, targetEntity = className.class)
@JoinColumn(name = "myClass_id")
@JsonView(SerializationView.Summary.class)
private Collection<Model> ModelObjects;

此外,这些集合连接在同一列上。

为了解决这个问题,我将其中一个集合更改为 FetchType.LAZY,因为它适合我的用例。

祝你好运!
~J

At my end, this happened when I had multiple collections with FetchType.EAGER, like this:

@ManyToMany(fetch = FetchType.EAGER, targetEntity = className.class)
@JoinColumn(name = "myClass_id")
@JsonView(SerializationView.Summary.class)
private Collection<Model> ModelObjects;

Additionally, the collections were joining on the same column.

To solve this issue, I changed one of the collections to FetchType.LAZY since it was okay for my use-case.

Goodluck!
~J

暖阳 2024-10-12 10:14:49

您还可以尝试使 fetch=FetchType.LAZY 并将 @Transactional(readOnly = true) 添加到获取子项的方法中

You can also try to make fetch=FetchType.LAZY and just add @Transactional(readOnly = true) to method where you get child

腹黑女流氓 2024-10-12 10:14:49

TLDR:不要使用 EAGER。始终仅在您真正需要时才取东西


这里提到了很多关于 FetchType.EAGER 的内容,我想更详细地说明为什么这是一个坏主意以及应该使用什么。希望读完本文后您意识到您绝对不应该永远使用FetchType.EAGER

只是没有充分的理由!这是一个市长陷阱,可能会在未来咬住你(甚至更糟糕的是其他人)。假设您为学生选择了 FetchType.EAGER ->老师关系,因为你认为每次你需要去接学生时,你也需要他的老师。现在,即使您现在百分百确定自己永远不需要没有老师的学生,您也无法预见需求将如何变化。 FetchType.EAGER 违反了开闭原则!您的代码不再开放扩展 - 如果以后需要加载没有教师的学生,那么在不重新设计(并且可能破坏)现有代码的情况下很难做到这一点!

您遇到的一个更大的问题是,您基本上为将来可能的查询创建了一个 n+1 选择问题,(正确地)已经在基本查询中获取了另一个包。假设将来有人想要加载所有学生的成绩,其中有 30000 个。既然你告诉 Hibernate EAGER 获取所有教师,它就必须这样做。但由于您已经在同一查询中获取了另一个“包”(成绩),这实际上会导致 30001 次查询 - 对于该场景中甚至不需要的数据!第一个查询加载所有学生+成绩,然后为每个学生单独查询以获取他的老师。不用说,这对于性能来说是可怕的。在我看来,这是人们相信“Hibernate 很慢”的唯一原因 - 他们只是没有意识到在某些情况下它可能查询东西的效率有多低。你真的必须小心 1:n 关系。

3 个替代方案(需要时手动获取内容):

  1. 使用 JOIN FETCH 获取集合。继续使用示例 SELECT Stud FROM STUDENT Stud JOIN FETCH Stud.teachers 就可以了。这将始终触发一个查询来获取学生和教师。请注意,仅以这种方式获取一个集合(对于这个答案来说解释太过分了)。
  2. 如果您使用 Spring-JPA,您可以使用 @EntityGraph(attributePaths = {"teachers"}) 来执行相同的操作。
  3. 您可以使用 Hibernate 代理调用 Hibernate.initialize(oneStudent.getTeachers()) 来手动获取关系。这将始终创建一个单独的查询,因此不要在循环中执行它,否则您只是自己创建了一个 n+1 选择问题。

最后还有一个一般提示:将 org.hibernate.SQL 的日志记录设置为 DEBUG,以查看何时/触发哪些查询,并确保本地开发设置具有合理数量的数据。当您仅与 2 名学生测试代码并且不检查触发的查询时,您可能会错过类似的内容,并最终在具有更多数据的真实系统上出现问题。

TLDR: Don't use EAGER. Always fetch things only when you really need them!


A lot of mentions here about FetchType.EAGER and I wanted to go a bit more into detail why this is a bad idea and on what to use alternatively. Hopefully after reading this you realize that really you should absolutely NEVER use FetchType.EAGER.

There is just no good reason to! It's a mayor pitfall that can bite you (or even worse: someone else) down the road. Imagine you chose FetchType.EAGER for a Student -> Teacher relation, because you think every time you need to fetch a Student you also need his Teachers. Now even if you are 100% sure you never need students without teachers right now, you simply can't foresee how requirements change. FetchType.EAGER violates the Open-closed principle! Your code is no longer open for extension - if later the need for loading Students without Teachers arise it's difficult do to that without reworking (and possibly breaking) existing code!

An even bigger problem you have is that you basically created an n+1 select problem for possible future queries, that (rightfully) already fetched another bag in the basic query. Let's say in the future someone wants to load all Students with their grades and there are 30000 of them. Since you told Hibernate to EAGER fetch all Teachers it has to do that. But since you already fetched another "bag" (the grades) within the same query this actually results in 30001 queries - for data that wasn't even needed in that scenario! The first query for loading all Students+Grades and then a separate query for each Student to fetch his teachers. Needless to say that this is horrendous for performance. In my opinion this is the sole reason for people to believe that "Hibernate is slow" - they just don't realize how incredible inefficient it might query stuff in some situations. You really have to be careful with 1:n relations.

3 Alternatives (manually fetch stuff when needed):

  1. Use JOIN FETCH to fetch a collection. To stick with the example SELECT stud FROM STUDENT stud JOIN FETCH stud.teachers would do the trick. This will always fire a single query to fetch students AND teachers. Just be mindful to only fetch one collection that way (explanation would go too far for this answer).
  2. If you use Spring-JPA you can use @EntityGraph(attributePaths = {"teachers"}) to do the same.
  3. You could call Hibernate.initialize(oneStudent.getTeachers()) with the Hibernate-proxy to fetch the relation manually. This will always create a separate query, so don't do it in a loop or you just created a n+1 select problem yourself.

Also one final tip in general: turn the logging for org.hibernate.SQL to DEBUG to see when/what queries are fired and make sure your local dev setup has a reasonable amount of data. When you test your code with only 2 students and don't check the queries that are fired you might miss something like that and end up having issues on real systems with more data.

初雪 2024-10-12 10:14:49

注释 FetchLazyCollection 有时有助于运行项目。

@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.FALSE)

Commenting both Fetch and LazyCollection sometimes helps to run project.

@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.FALSE)
雨后咖啡店 2024-10-12 10:14:49

@LazyCollection(LazyCollectionOption.FALSE) 的一个好处是,带有此注释的多个字段可以共存,而 FetchType.EAGER 则不能共存,即使在这种共存是合法的情况下也是如此。

例如,Order 可能有一个 OrderGroup 列表(很短)以及一个 Promotions 列表(也很短)。 @LazyCollection(LazyCollectionOption.FALSE) 可以在两者上使用,而不会导致 LazyInitializationExceptionMultipleBagFetchException

就我而言,@Fetch 确实解决了我的 MultipleBacFetchException 问题,但随后导致了 LazyInitializationException,即臭名昭著的 no Session 错误。

One good thing about @LazyCollection(LazyCollectionOption.FALSE) is that several fields with this annotation can coexist while FetchType.EAGER cannot, even in the situations where such coexistence is legit.

For example, an Order may have a list of OrderGroup(a short one) as well as a list of Promotions(also short). @LazyCollection(LazyCollectionOption.FALSE) can be used on both without causing LazyInitializationException neither MultipleBagFetchException.

In my case @Fetch did solve my problem of MultipleBacFetchException but then causes LazyInitializationException, the infamous no Session error.

橘和柠 2024-10-12 10:14:49

我通过注释解决了:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)

I solved by annotating:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
遗失的美好 2024-10-12 10:14:49

好的,这是我的 2 美分。我在实体中有 Fetch Lazy 注释,但我也在会话 bean 中复制了 fetch Lazy 注释,从而导致了多包问题。 中的行

所以我只是删除了 SessionBean criteria.createAlias("FIELD", "ALIAS", JoinType.LEFT_OUTER_JOIN); //REMOVED

我在调用 Listparent = criteria.list 后想要检索的列表上使用了 Hibernate.initialize 。
Hibernate.initialize(parent.getChildList());

Ok so here's my 2 cents. I had the Fetch Lazy annotations in my Entity but I also duplicated the fetch lazy in the session bean thus causing a multiple bag issue. So I just removed the lines in my SessionBean

criteria.createAlias("FIELD", "ALIAS", JoinType.LEFT_OUTER_JOIN); //REMOVED

And I used Hibernate.initialize on the list I wanted to retrieve after the List parent = criteria.list was called.
Hibernate.initialize(parent.getChildList());

无力看清 2024-10-12 10:14:49

您可以使用新的注释来解决这个问题:

@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)

事实上,fetch 的默认值也是 FetchType.LAZY。

You could use a new annotation to solve this:

@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)

In fact, fetch's default value is FetchType.LAZY too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文