Hibernate 1+N问题及解决

1+N问题:

如果在一个对象里关联另一个对象,同时fetchType为eager,比如最典型的ManyToOne。当你要取many中的对象时,这些被关联对象都会单独再发1条sql,本来应该发1条sql就能解决的问题实际发了1+N条sql,形成1+N问题。

1+N问题重现:

package com.hibernate.demo.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Msg {
    private int id;
    private String name;
    private Topic topic;
    
    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToOne
    @JoinColumn(name="topicId")
    public Topic getTopic() {
        return topic;
    }
    public void setTopic(Topic topic) {
        this.topic = topic;
    }
}
package com.hibernate.demo.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Topic {
    private int id;
    private String name;
    private Set<Msg> msgs = new HashSet<Msg>();
    @OneToMany(mappedBy="topic")
    public Set<Msg> getMsgs() {
        return msgs;
    }
    public void setMsgs(Set<Msg> msgs) {
        this.msgs = msgs;
    }
    @Id
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
}

以上代码映射如下表结构:

image  image

 

当我要查询所有的msg时,使用如下代码:

@Test
    public void testLoad(){
        Session s = sf.getCurrentSession();
        s.beginTransaction();
        
        Query q = s.createQuery("from Msg");
        for(Object obj : q.list()){
            Msg m = (Msg)obj;
            System.out.println(m.getName());
        }
        
        s.getTransaction().commit();
    }

实际执行的查询语句如下:

image

如此,本来应该只执行第一句的,却附加了后面多余的N次查询,故叫做1+N问题。对于OneToMany,一旦设定fetch=FetchType.EAGER,也会出现该问题;

 

1+N问题的解决

解决方案1:设置fetch= FetchType.LAZY;

解决方案2:使用join fetch,即表连接查询

解决方案3:使用@BatchSize标签,减少不必要的查询次数,但不能从根本上解决;

最佳实践是在1,2两种方案中选择,具体视情况而定。

posted @ 2013-04-04 20:38  寻梦丄天涯  阅读(468)  评论(0编辑  收藏  举报