我很难强迫Hibernate在获取数据时使用两个表之间的联接。我们有一个大型父表和一个大型子表,由多列连接(没有单一的ID列(。当我们获取父记录时,Hibernate急切地获取子记录,但它使用单独的查询来完成,每个父记录一个查询。与只有一个带有联接的查询相比,这似乎非常慢
但是,如何让Hibernate进行连接呢?
以下是实体(这只是一个匿名示例(:
@Entity
@Table(name = "BOOKS")
public class Book
{
@EmbeddedId
private BookID id;
@Column(name = "DESCRIPTION")
private String description;
@Column(name = "PUBLISH_DATE")
private Date publishDate;
@OneToMany(mappedBy = "book", fetch = EAGER, cascade = ALL, orphanRemoval = true)
private List<BookReview> reviews;
}
@Entity
@Table(name = "BOOK_REVIEWS")
public class BookReview
{
@EmbeddedId
private BookReviewID id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "TITLE", referencedColumnName = "TITLE"),
@JoinColumn(name = "AUTHOR_FIRST_NAME", referencedColumnName = "AUTHOR_FIRST_NAME"),
@JoinColumn(name = "AUTHOR_LAST_NAME", referencedColumnName = "AUTHOR_LAST_NAME")
})
private Book book;
@Column(name = "UPDATE_DATE")
private Date updateDate;
}
以及它们的嵌入式密钥:
@Embeddable
public class BookID
{
@Column(name = "TITLE")
private String title;
@Column(name = "AUTHOR_FIRST_NAME")
private String authorFirstName;
@Column(name = "AUTHOR_LAST_NAME")
private String authorLastName;
}
@Embeddable
public class BookReviewID extends BookID
{
@Column(name = "USERNAME")
private String userName;
}
当我对BOOK
中的所有记录运行查询时(使用entityManager.createQuery("from Book")
(,它会对BOOK表运行查询以获取所有记录,然后对每个记录的评论进行单独的查询。与其对每本书的每组评论进行单独的查询,不如一开始只做一个left outer join
来获取它们。
这甚至可以通过注释实现吗?或者我必须使用CriteriaBuilder
或查询语言吗?
我应该注意的是,添加@Fetch(FetchMode.JOIN)
并不会改变它似乎在做什么。
Hibernate文档强烈建议使用fetch = FetchType.LAZY
而不是fetch = FetchType.EAGER
:
如果您忘记了
JOIN FETCH
所有EAGER
关联,Hibernate将为每一个关联发出一个辅助选择,这反过来会导致N+1查询问题。出于这个原因,你应该更喜欢LAZY协会。
因此,我建议您更正此关联:
@OneToMany(mappedBy = "book", fetch = EAGER, cascade = ALL, orphanRemoval = true)
private List<BookReview> reviews;
到此:
@OneToMany(mappedBy = "book", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<BookReview> reviews;
然后通过在HQL中使用CCD_ 10来覆盖加入的关联的惰性,如下所示:
entityManager.createQuery(
"select b from Book b join fetch b.reviews"
)
对于@Fetch(FetchMode.JOIN)
,如文件中所述:
我们之所以不使用JPQL查询来获取多个实体,是因为
FetchMode.JOIN
策略将被查询获取指令覆盖因此,当实体通过其标识符或natural-id直接提取时,
FetchMode.JOIN
非常有用此外,
FetchMode.JOIN
充当FetchType.EAGER
策略。即使我们将关联标记为FetchType.LAZY
,FetchMode.JOIN
也会急切地加载该关联。
因此,FetchMode.JOIN
将仅适用于以下直接获取:
Book book = entityManager.find(Book.class, new BookID(...));