Hibernate 为 @ManyToOne JPA 注释属性创建 N+1 个查询

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 中获取所有记录会好得多。实际上,我觉得奇怪为什么它不是默认行为。

那么,我该怎么做呢?

Vla*_*cea 6

这里的问题与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 执行的语句数。


Pre*_*ric 2

尝试用

session.createQuery("select i from InvoiceItem i join fetch i.invoice inv").list();
Run Code Online (Sandbox Code Playgroud)

它应该使用连接在单个 SQL 查询中获取所有数据。