Java Can';t获取并加入延迟初始化的集合
由于MultipleBagFetchException,我无法执行简单的fetchjoinJava Can';t获取并加入延迟初始化的集合,java,hibernate,Java,Hibernate,由于MultipleBagFetchException,我无法执行简单的fetchjoin @Entity public class Person { @OneToMany(mappedBy="person",fetch=FetchType.LAZY) private List<Auto> autos; } @Entity public class Auto { @ManyToOne @JoinColumn(name = "person
@Entity
public class Person {
@OneToMany(mappedBy="person",fetch=FetchType.LAZY)
private List<Auto> autos;
}
@Entity
public class Auto {
@ManyToOne
@JoinColumn(name = "person_id", nullable = false)
private Person person;
@OneToMany(mappedBy="auto",fetch=FetchType.LAZY)
private List<Tool> tools;
}
@Entity
@Table(name="tool")
public class Tool {
@ManyToOne
@JoinColumn(name = "auto_id", nullable = false)
private Auto auto;
}
我已经读过有关此异常的内容,但在这些情况下,出现此异常的原因是对集合使用了EAGER fetch类型。这个怎么样?这是最简单的实体关系
最重要的是,假设我们不允许接触实体。
如何仅在查询端解决此问题?有一种方法可以避免n+1查询而不触及实体,只更改findAll的查询。我们可以编写一个包装器函数,它将首先向用户加载汽车,然后用户在一次选择中获取所有工具 PersonRepository
@Query("SELECT distinct p FROM Person p JOIN FETCH p.autos a")
List<Person> findAll();
生成的第二个查询将是:
SELECT
auto0_.id AS id1_0_0_,
tools1_.id AS id1_8_1_,
auto0_.name AS name2_0_0_,
auto0_.person_id AS person_i3_0_0_,
tools1_.auto_id AS auto_id3_8_1_,
tools1_.name AS name2_8_1_,
tools1_.auto_id AS auto_id3_8_0__,
tools1_.id AS id1_8_0__
FROM
Auto auto0_
INNER JOIN
Tool tools1_
ON
auto0_.id=tools1_.auto_id
WHERE
auto0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
除此之外,我认为我们的选项是有限的,我们必须更改工具实体获取模式或为默认获取模式添加BatchSize。选择此选项以便在单独的查询中获取工具
@OneToMany(mappedBy = "auto", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Tool> tools;
在多个集合获取的情况下解决MultipleBagFetchException并非易事。请注意,在您的查询中,您正在急切地获取多个集合(JOIN FETCH)。[参考此答案]()了解可能的解决方案。您可以尝试不加入FETCH工具,让它在访问时惰性地加载。或者更改列表以设置实体是否有更新的机会。因此,在这种情况下,如果我们不想接触实体本身,基本上是不可能避免n+1查询的?
List<Person> persons = personRepository.findAll();
Session session = (Session) entityManager.getDelegate();
List<Auto> autos = new ArrayList<>();
for (Person person : persons) {
if(!CollectionUtils.isEmpty(person.getAutos())) {
autos.addAll(person.getAutos());
}
}
try{
autos = session.createQuery("select distinct a from Auto a Join fetch a.tools " +
" where a in :autos", Auto.class)
.setParameter("autos", autos)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
} catch (Exception ex) {
ex.printStackTrace();
}
SELECT DISTINCT
person0_.id AS id1_6_0_,
autos1_.id AS id1_0_1_,
person0_.name AS name2_6_0_,
autos1_.name AS name2_0_1_,
autos1_.person_id AS person_i3_0_1_,
autos1_.person_id AS person_i3_0_0__,
autos1_.id AS id1_0_0__
FROM
Person person0_
INNER JOIN
Auto autos1_
ON
person0_.id=autos1_.person_id
SELECT
auto0_.id AS id1_0_0_,
tools1_.id AS id1_8_1_,
auto0_.name AS name2_0_0_,
auto0_.person_id AS person_i3_0_0_,
tools1_.auto_id AS auto_id3_8_1_,
tools1_.name AS name2_8_1_,
tools1_.auto_id AS auto_id3_8_0__,
tools1_.id AS id1_8_0__
FROM
Auto auto0_
INNER JOIN
Tool tools1_
ON
auto0_.id=tools1_.auto_id
WHERE
auto0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
@OneToMany(mappedBy = "auto", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Tool> tools;
SELECT
tools0_.auto_id AS auto_id3_8_1_
, tools0_.id AS id1_8_1_
, tools0_.id AS id1_8_0_
, tools0_.auto_id AS auto_id3_8_0_
, tools0_.name AS name2_8_0_
FROM
Tool tools0_
WHERE
tools0_.auto_id IN
(
SELECT
autos1_.id
FROM
Person person0_
INNER JOIN
Auto autos1_
ON
person0_.id=autos1_.person_id
)