我有这些课程:
@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中获取会好得多。实际上,我觉得奇怪的是为什么它不是默认行为。
那么,我该怎么做呢?
4条答案
按热度按时间vd2z7a6w1#
这里的问题与Hibernate无关,而是与JPA有关。
在JPA 1.0之前,Hibernate 3对所有关联使用延迟加载。
但是,JPA 1.0规范仅将
FetchType.LAZY
用于集合关联:@OneToMany
,@ManyToMany
@ElementCollection
)默认情况下,
@ManyToOne
和@OneToOne
关联使用FetchType.EAGER
,从性能Angular 来看,这非常糟糕。这里描述的行为被称为[N +1查询问题][5],它的发生是因为Hibernate需要确保
@ManyToOne
关联在返回结果给用户之前已经初始化。现在,如果通过
entityManager.find
使用直接获取,Hibernate可以使用LEFT JOIN来初始化FetchTYpe.EAGER
关联。但是,当执行一个没有显式使用JOIN FETCH子句的查询时,Hibernate不会使用JOIN来获取
FetchTYpe.EAGER
关联,因为它不能改变您已经指定了如何构造的查询,所以它只能使用辅助查询。修复方法很简单,只需对所有关联使用
FetchType.LAZY
:此外,应该使用Hypersistence Utils来AssertJPA和Hibernate执行的语句数。
bhmjp9jg2#
试试
它应该使用连接在单个SQL查询中获取所有数据。
4xrmg8kj3#
是的,有您需要的设置:
@BatchSize(size=25)
。请在此处查看:20.1.5.使用批量取数
使用批处理获取,Hibernate可以在访问一个代理时加载多个未初始化的代理。批处理获取是惰性选择获取策略的优化。有两种方法可以配置批处理获取:在类级别和集合级别上。
类/实体的批量获取更容易理解。考虑以下示例:在运行时,在一个会话中加载了25个Cat示例,并且每个Cat都有一个对其所有者Person的引用。Person类Map有一个代理,lazy=“true”。如果您现在遍历所有Cat并对每个Cat调用getOwner(),Hibernate将默认执行25个SELECT语句来检索代理的所有者。您可以通过在Person:
指定了这个批处理大小后,Hibernate现在将在需要访问未初始化的代理时按需执行查询,如上所述,但不同之处在于,它将一次查询更多Person的所有者,而不是查询正在访问的代理实体,因此,当访问其他人的所有者时,它可能已经被该批获取初始化,而将仅执行几个(远少于25个)查询。
因此,我们可以在以下两个方面使用该注解:
也可以在这里查看:
gajydyqb4#
在此方法中,触发了多个SQL。触发第一个SQL是为了检索父表中的所有记录。触发其余SQL是为了检索每个父记录的记录。第一个查询从数据库中检索M个记录,在本例中是M个父记录。对于每个父记录,新查询将检索子记录。