zoukankan      html  css  js  c++  java
  • 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两种方案中选择,具体视情况而定。

  • 相关阅读:
    TeamViewer14
    mysql 导出表结构和表数据 mysqldump用法
    虚拟机中不能上外网
    Mysql初始化root密码和允许远程访问
    常用sql语句
    查看连接MYSQL数据库的IP信息
    设置linux下shell显示不同颜色的字体
    常用mysql导入导出数据的命令
    spring boot 以jar的方式启动常用shell脚本
    idea的properties文件乱码问题解决
  • 原文地址:https://www.cnblogs.com/huntdream/p/2999796.html
Copyright © 2011-2022 走看看