• 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两种方案中选择,具体视情况而定。

  • 相关阅读:
    socket入门教程
    线程间操作无效: 从不是创建控件“xxxxxxxx”的线程访问它。
    Socket教程
    Windows 2008 R2防火墙,允许被ping
    Miller_rabin算法+Pollard_rho算法 POJ 1811 Prime Test
    Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法
    Miller-Rabin算法 codevs 1702 素数判定 2
    快速幂 cojs 1130. 取余运算
    中国剩余定理 hdu 3579
    中国剩余定理 hdu 1573 X问题
  • 原文地址:https://www.cnblogs.com/huntdream/p/2999796.html
Copyright © 2020-2023  润新知