我有这些课程:
@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
}
当我运行此查询时:
session.createQuery("select i from InvoiceItem i").list();
它执行一个查询以从InvoiceItem中选择记录,如果我有10000个发票项,则会生成10000个其他查询以从每个InvoiceItem中选择发票。
我认为如果所有记录都可以在单个sql中获取,那将会更好。实际上,我觉得很奇怪为什么它不是默认行为。
那么,我该怎么做呢?
答案 0 :(得分:2)
尝试
session.createQuery("select i from InvoiceItem i join fetch i.invoice inv").list();
它应该通过使用连接来获取单个SQL查询中的所有数据。
答案 1 :(得分:1)
这里的问题与Hibernate无关,而与JPA有关。
在JPA 1.0之前,Hibernate 3对所有关联都使用延迟加载。
但是,JPA 1.0规范仅将FetchType.LAZY
用于集合关联:
@ManyToOne
和@OneToOne
关联默认使用FetchType.EAGER
,即very bad from a performance perspective。
此处描述的行为称为N+1 query issue,它的发生是因为Hibernate需要确保@ManyToOne
关联已初始化,然后才能将结果返回给用户。
现在,如果您正在通过entityManager.find
使用直接获取,则Hibernate可以使用LEFT JOIN来初始化FetchTYpe.EAGER
关联。
但是,当执行不显式使用JOIN FETCH子句的查询时,Hibernate将不会使用JOIN来获取FetchTYpe.EAGER
关联,因为它无法更改已经指定了构造方式的查询。因此,它只能使用辅助查询。
修复很简单。只需对所有关联使用FetchType.LAZY
:
@ManyToOne(获取= FetchType.LAZY) @JoinColumn(名称=“发票编号”,可插入=假,可更新=假) 私人发票发票;
更多,您应该使用db-util project声明由JPA和Hibernate执行的语句数。有关更多详细信息,请查看this article。
答案 2 :(得分:0)
是的,您需要设置: @BatchSize(size=25)
。在这里查看:
小引用:
使用批量提取,如果访问一个代理,Hibernate可以加载几个未初始化的代理。批量提取是延迟选择提取策略的优化。您可以通过两种方式配置批量提取:在类级别和集合级别。
更容易理解批量提取类/实体。请考虑以下示例:在运行时,您在会话中加载了25个Cat实例,并且每个Cat都有一个对其所有者的引用,即Person。 Person类使用代理映射,lazy =" true"。如果您现在遍历所有猫并在每个猫上调用getOwner(),默认情况下,Hibernate将执行25个SELECT语句来检索代理所有者。您可以通过在Person:
的映射中指定批量大小来调整此行为
<class name="Person" batch-size="10">...</class>
如果指定了这个批量大小,Hibernate现在将在需要访问未初始化代理时按需执行查询,如上所述,但区别在于它不会查询正在访问的确切代理实体,而是查询更多Person&# 39; s所有者,因此,当访问其他人的所有者时,它可能已经通过此批量提取初始化,只执行少量(少于25个)查询。
因此,我们可以在两者上使用该注释:
在这里查看:
答案 3 :(得分:-1)
在此方法中,有多个SQL被触发。触发第一个用于检索Parent表中的所有记录。其余的被触发以检索每个父记录的记录。第一个查询从数据库中检索M个记录,在本例中为M个父记录。对于每个Parent,新查询将检索Child。