Mat*_*ari 7 java hibernate jpa many-to-one select-n-plus-1
我有这些课程:
@Entity
public class Invoice implements Serializable {
@Id
@Basic(optional = false)
private Integer number;
private BigDecimal value;
//Getters and setters
}
@Entity
public class InvoiceItem implements Serializable {
@EmbeddedId
protected InvoiceItemPK invoiceItemPk;
@ManyToOne
@JoinColumn(name = "invoice_number", insertable = false, updatable = false)
private Invoice invoice;
//Getters and setters
}
Run Code Online (Sandbox Code Playgroud)
当我运行此查询时:
session.createQuery("select i from InvoiceItem i").list();
Run Code Online (Sandbox Code Playgroud)
它执行一个查询以从 InvoiceItem 中选择记录,如果我有 10000 个发票项目,它会生成 10000 个附加查询以从每个 InvoiceItem 中选择发票。
我认为如果可以在单个 sql 中获取所有记录会好得多。实际上,我觉得奇怪为什么它不是默认行为。
那么,我该怎么做呢?
这里的问题与Hibernate无关,而是与JPA有关。
在 JPA 1.0 之前,Hibernate 3 对所有关联使用延迟加载。
但是,JPA 1.0 规范FetchType.LAZY
仅用于集合关联:
在@ManyToOne
和@OneToOne
协会使用FetchType.EAGER
默认情况下,这是非常糟糕的从性能的角度。
此处描述的行为称为 [N+1 查询问题][5],发生这种情况是因为 Hibernate 需要确保@ManyToOne
在将结果返回给用户之前已初始化关联。
现在,如果您使用通过直接获取entityManager.find
,Hibernate 可以使用 LEFT JOIN 来初始化FetchTYpe.EAGER
关联。
但是,当执行未显式使用 JOIN FETCH 子句的查询时,Hibernate 不会使用 JOIN 来获取FetchTYpe.EAGER
关联,因为它无法更改您已经指定如何构造的查询。因此,它只能使用辅助查询。
修复很简单。仅FetchType.LAZY
用于所有关联:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "invoice_number", insertable = false, updatable = false)
private Invoice invoice;
Run Code Online (Sandbox Code Playgroud)
此外,您应该使用db-util 项目来断言 JPA 和 Hibernate 执行的语句数。
尝试用
session.createQuery("select i from InvoiceItem i join fetch i.invoice inv").list();
Run Code Online (Sandbox Code Playgroud)
它应该使用连接在单个 SQL 查询中获取所有数据。
归档时间: |
|
查看次数: |
5381 次 |
最近记录: |