問題背景:
在設計一個樹形結構的實體中用到了多對一,一對多的映射關係,在加載其關聯對象的時候,爲了性能考慮,很自然的想到了懶加載。
也因此遇到了N+1的典型問題 : 通常1的這方,通過1條SQL查找得到1個對象,而JPA基於Hibernate,fetch策略默認爲select(並非聯表查詢),由於關聯的存在 ,又需要將這個對象關聯的集合取出,集合數量是N,則要發出N條SQL,於是本來的1條聯表查詢SQL可解決的問題變成了N+1條SQL
JPA 2.1推出來的@EntityGraph、@NamedEntityGraph用來提高查詢效率,很好地解決了N+1條SQL的問題。兩者需要配合起來使用,缺一不可。@NamedEntityGraph配置在@Entity上面,而@EntityGraph配置在Repository的查詢方法上面.通過聯表查詢進行解決。
解決的方法如下 :
Demo 如下:
1 . 首先在實體上面註解@NamedEntityGraph,指明name供查詢方法使用,attributeNodes 指明被標註爲懶加載的屬性節點
@Entity
@Getter
@Setter
@Table(name = "ORG_AGENCY")
@NamedEntityGraph(name = "Agency.Graph", attributeNodes = {@NamedAttributeNode("region"), @NamedAttributeNode("parent"),@NamedAttributeNode("mofDep"),@NamedAttributeNode("unit")})
public class Agency extends BaseEntity {
@Field
@Column(nullable = false)
@ApiModelProperty(value = "編碼", required = true)
private String code;
@Field
@Column(nullable = false)
@ApiModelProperty(value = "名稱", required = true)
private String name;
@ApiModelProperty(value = "是否啓用")
private Boolean enabled; // 是否啓用
@ApiModelProperty(value = "級次")
private Integer levelNum;
@ApiModelProperty(value = "內部編碼")
private String innerCode;
@ApiModelProperty(value = "是否末級")
private Boolean leafNode;
@ApiModelProperty(value = "是否允許增加下級")
private Boolean expandable;
@ApiModelProperty(value = "所屬區劃")
@ManyToOne(fetch = FetchType.LAZY)
private Region region;
@ManyToOne(fetch = FetchType.LAZY)
@ApiModelProperty(value = "上級")
private Agency parent;
@ApiModelProperty(value = "年度")
private String year;
@ApiModelProperty(value = "業務處室")
@ManyToOne(fetch = FetchType.LAZY)
private MOFDep mofDep;
@ApiModelProperty(value = "來源單位")
@ManyToOne(fetch = FetchType.LAZY)
private Organization unit;
}
2 . 在訪問的dao的查詢方法上面註解@EntityGraph,value屬性值爲@NamedEntityGraph的name屬性值,如 AgencyRepository :
public interface AgencyRepository extends GenericRepository<Agency> {
@QueryHints(value = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})
@EntityGraph(value = "Agency.Graph", type = EntityGraph.EntityGraphType.FETCH)
List<Agency> findAll(Predicate predicate, Sort sort);
}