blo*_*low 428 java hibernate jpa
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;
}
Run Code Online (Sandbox Code Playgroud)
Child.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
Run Code Online (Sandbox Code Playgroud)
这个问题怎么样?我能做什么?
编辑
好吧,我遇到的问题是另一个"父"实体在我父母的内部,我的真实行为是这样的:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private AntoherParent anotherParent;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<Child> children;
}
Run Code Online (Sandbox Code Playgroud)
AnotherParent.java
@Entity
public AntoherParent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<AnotherChild> anotherChildren;
}
Run Code Online (Sandbox Code Playgroud)
Hibernate不喜欢两个集合FetchType.EAGER,但这似乎是一个bug,我没有做不寻常的事情......
删除FetchType.EAGER从Parent或AnotherParent解决问题,但我需要它,所以真正的解决方案是使用@LazyCollection(LazyCollectionOption.FALSE)的,而不是FetchType(感谢Bozho的解决方案).
Boz*_*zho 513
我认为更新版本的hibernate(支持JPA 2.0)应该可以解决这个问题.但是否则你可以通过使用以下方法注释集合字段来解决它:
@LazyCollection(LazyCollectionOption.FALSE)
Run Code Online (Sandbox Code Playgroud)
请记住fetchType从@*ToMany注释中删除该属性.
但请注意,在大多数情况下,a Set<Child>更合适List<Child>,所以除非你真的需要List- 去吧Set
小智 279
只需从List类型更改为Set类型.
Dav*_*Rlz 124
或者,在代码中添加特定于Hibernate的@Fetch注释:
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;
Run Code Online (Sandbox Code Playgroud)
这应该解决与Hibernate bug HHH-1718相关的问题
小智 28
在尝试了这篇文章和其他文章中描述的每一个选项之后,我得出的结论是修复是如下.
在每个XToMany地方@ XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
和中间之后
@Fetch(value = FetchMode.SUBSELECT)
Run Code Online (Sandbox Code Playgroud)
这对我有用
Pra*_*ngh 20
要修复它,只需Set代替List嵌套对象.
@OneToMany
Set<Your_object> objectList;
Run Code Online (Sandbox Code Playgroud)
并且不要忘记使用 fetch=FetchType.EAGER
它会工作.
CollectionId如果你只想坚持使用列表,那么Hibernate 还有一个概念.
Chr*_*ler 11
我发现了一篇关于Hibernate在这种对象映射中的行为的博客文章:http://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html
这个问题一直是StackOverflow或Hibernate论坛上反复出现的主题,因此我决定也将答案变成一篇文章。
考虑到我们具有以下实体:
并且,您希望Post与所有comments和tags集合一起获取一些父实体。
如果您使用多个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();
Run Code Online (Sandbox Code Playgroud)
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
]
Run Code Online (Sandbox Code Playgroud)
Hibernate不允许获取一个以上的包,因为这会生成笛卡尔积。
现在,您会发现很多答案,博客文章,视频或其他资源,它们告诉您对集合使用a Set代替List。
那是可怕的建议。不要那样做!
使用Sets而不是Lists将MultipleBagFetchException消失,但笛卡尔乘积仍将存在,实际上甚至更糟,因为在应用此“修复”后很长时间您会发现性能问题。
您可以执行以下技巧:
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();
Run Code Online (Sandbox Code Playgroud)
在第一个JPQL查询中,
distinct不要转到SQL语句。因此,我们将PASS_DISTINCT_THROUGHJPA查询提示设置为false。DISTINCT在JPQL中有两个含义,在这里,我们需要它对
getResultListJava端而不是SQL端返回的Java对象引用进行重复数据删除。请查看本文以获取更多详细信息。
只要您使用最多获取一个集合JOIN FETCH,就可以了。
通过使用多个查询,您将避免使用笛卡尔积,因为除第一个集合外,其他任何集合都是使用辅助查询来获取的。
如果您FetchType.EAGER在映射时间为@OneToMany或@ManyToMany关联时使用该策略,那么您很容易以结束MultipleBagFetchException。
最好从切换到FetchType.EAGER,Fetchype.LAZY因为急切的获取是一个可怕的想法,可能会导致严重的应用程序性能问题。
避免FetchTYpe.EAGER并且不要从切换到List,Set仅仅是因为这样做会使Hibernate隐藏MultipleBagFetchException在地毯下面。一次只获取一个集合,就可以了。
只要您使用与要初始化的集合相同数量的查询来执行此操作,就可以了。只是不要在循环中初始化集合,否则会触发N + 1个查询问题,这也对性能不利。
您可以在JPA中保留EAGER展位列表,并在其中至少添加一个JPA注释@OrderColumn(显然是要订购的字段的名称).不需要特定的休眠注释.但请记住,如果所选字段的值不是从0开始,它可能会在列表中创建空元素
[...]
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OrderColumn(name="orderIndex")
private List<Child> children;
[...]
Run Code Online (Sandbox Code Playgroud)
在儿童中,您应该添加orderIndex字段
| 归档时间: |
|
| 查看次数: |
285378 次 |
| 最近记录: |