一、问题介绍
fetch = FetchType.LAZY 懒加载,使用时才加载
fetch = FetchType.EAGER 立即加载
当实体类中存在@OneToMany(fetch = FetchType.LAZY)注解时,表示这个字段使用的是懒加载方式。这种方式在查询时不会真正调用SQL,只有在后续使用时才会调用。例如Product实体类中存在一对多的字段parameters:
@Entity
public class Product {
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
private List<Parameter> parameters;
}
当你查询product时,并不会调用查询parameters的SQL语句,只有在使用product时才会调用:
product.getParameters().size(); //此时调用SQL语句查询parameters,但会调用N+1此SQL
此时调用N+1次SQL完成parameters的查询,消耗大量时间,因此有些情况下,我们希望在查询product时就把parameters也查询出来。这个解决方法便是实体图。
二、实体图 Entity Graph
实体图可以指定如何获取实体以及实体关联的实体。在Srping Data JPA中提供了 @NamedEntityGraph 和 @EntityGraph 注解用于定义和使用实体图。
此处参考博客# 使用EntityGraph解决JPA下N+1问题 中的示例,假设目前的问题为:A--oneToMany-->B--oneToMany-->C,如果需要通过实体图完成一次性加载,需要两步:
- 在实体类A上添加 @NamedEntityGraph 注解,用于定义实体图:
@NamedEntityGraph(
name = "aWithBWithC",
attributeNodes = {
@NamedAttributeNode(value = "bs", subgraph = "bWithC")},
subgraphs = {
@NamedSubgraph(name = "bWithC",
attributeNodes = {@NamedAttributeNode("cs")})
}
)
@Entity
@Table(name = "a", catalog = "funny", schema = "testing")
public class A {
@OneToMany(fetch = FetchType.LAZY)
@JoinTable( //if you have a table a_b for this relationship. Not related to the topic of entityGraph though.
name = "a_b",
joinColumns = @JoinColumn(name = "a_id"),
inverseJoinColumns = @JoinColumn(name = "b_id")
)
private Set<B> bs;
}
name = "aWithBWithC"定义实体图名称。attributeNodes =表示当前层要加载的内容。@NamedAttributeNode(value = "bs", subgraph = "bWithC")用于定义要加载的字段,字段为bs,使用bWithC这个分实体图加载。value =定义分实体图名称subgraphs =表示分实体图的信息,其中可以定义多个分实体图,分实体图由 @NamedSubgraph 表示,内容和 @NamedEntityGraph 相同。
- 然后在定义查询语句时,增加 @EntityGraph 注解:
public interface AsRepository extends PagingAndSortingRepository<A, Long> {
@EntityGraph(value = "aWithBWithC", type = EntityGraph.EntityGraphType.FETCH)
Page<Item> findAll(Pageable pageable); //FETCH will load all nested entity in one query.
}
@EntityGraph 的type字段有两个取值:
EntityGraph.EntityGraphType.FETCH //只有graph中指定的属性立即加载,其他所有属性强制懒加载
EntityGraph.EntityGraphType.LOAD //graph中指定的属性立即加载,其他属性保持原有加载策略
此时进行findAll查询时,就会自动将B和C也加载进来。