因为在设计一个树形结构的实体中用到了多对一,一对多的映射关系,在加载其关联对象的时候,为了性能考虑,很自然的想到了懒加载。
也由此遇到了N+1的典型问题 : 通常1的这方,通过1条SQL查找得到1个对象,而JPA基于Hibernate,fetch策略默认为select(并非联表查询),由于关联的存在 ,又需要将这个对象关联的集合取出,集合数量是N,则要发出N条SQL,于是本来的1条联表查询SQL可解决的问题变成了N+1条SQL
我采取的解决方法是 : 不修改懒加载策略,JPA也不写native SQL,通过联表查询进行解决。
如果对该例子比较感兴趣或者觉得言语表达比较啰嗦,可查看完整的demo地址 : https://github.com/EalenXie/springboot-jpa-N-plus-One
场景如下 :
我设计了一个典型的二叉树结构实体叫做Area,代表的含义是区域 (省、市、区)。省是树的一级根节点,市是省的子节点,区是市的子节点。如 : 广东省,广州市,天河区
1 . Area实体设计采用自关联,关联的子集fetch策略为懒加载。
package name.ealen.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.List; /** * Created by EalenXie on 2018/10/16 16:49. * 典型的 多层级 区域关系 */ @Entity @Table(name = "jpa_area") public class Area { /** * Id 使用UUID生成策略 */ @Id @GeneratedValue(generator = "UUID") @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") private String id; /** * 区域名 */ private String name; /** * 一个区域信息下面很多子区域(多级) 比如 : 广东省 (子)区域 : 广州市 (孙)子区域 : 天河区 */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") @JsonIgnore private Area parent; @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) private List<Area> children; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void