JPA解决sql查询过多的问题

 关于JPA、hibernate“臭名昭著”的n+1次查询导致的性能问题

问题重现举例:查询列表页面,当查询涉及多表关联时,即页面中除显示主表字段,还显示从表字段

期望:一个sql完成,即select a.c1, a.c2.... from a, b where a.id = b.fkid ......
实际:JPA会发送多个sql完成,第一条语句查询主表,后面发送n条语句查询子表,即所谓“n+1”问题,实测截图中的sql如下,共发送5条sql完成查询

修复方案:
1、在实体上面注解@NamedEntityGraph,指明name供查询方法使用,attributeNodes 指明被标注为懒加载的属性节点


2、在repository的查询方法上面注解@EntityGraph,value属性值为@NamedEntityGraph的name属性值


修复后,重新测试,只发送一个sql完成查询

@NamedEntityGraph的使用时为了解决sql查询过多的问题

@Entity
@Table(name="s_person")
@NamedEntityGraph(name="person.all",attributeNodes={@NamedAttributeNode("address"),@NamedAttributeNode("cards")})
public class Person {
    
    @GeneratedValue(generator = "uuid2")
        @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Id
    private String id;
    private String username;
    private String age;
    
    @OneToOne
    @JoinColumn(name="address_id",referencedColumnName="id")
    private Address address;
    
    
    
    @OneToMany(fetch=FetchType.EAGER)
    @JoinTable(name="s_person_card",joinColumns={@JoinColumn(name="p_id")}
    ,inverseJoinColumns={@JoinColumn(name="c_id")})
    private List<Cards> cards;
    
    public List<Cards> getCards() {
        return cards;
    }
    public void setCards(List<Cards> cards) {
        this.cards = cards;
    }
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
 
}
接口public interface PersonRepository extends JpaRepository<Person, String>{
 
    @EntityGraph(value = "person.all" , type=EntityGraphType.FETCH)
    Person findById(String id);
 
}
当去查询person的时候会自动查询Adress和Cards里面的内容,且只发出一条sql语句,这样就解决了是使用关联查询导致sql查询过多的问题

 

猜你喜欢

转载自blog.csdn.net/rainyear/article/details/86470426