zoukankan      html  css  js  c++  java
  • Hibernate之N+1问题

    什么是hibernate的N+1问题?先了解这样一个描述:

    多个学生可以对应一个老师,所以student(n)---teacher(1)。Stu类中有一个属性teacher。在hibernate配置文件中,Stu.hbm.xml中这样配置teacher

    <many-to-one name="teacher" class="com.ssh.shop.model.Account" lazy="false" >
            <column name="tid"/> <!--相当于 外键 -->
    </many-to-one>

    上面的 lazy="false",表示级联查询关联对象,但是当使用session.query()执行查询Student后打印sql语句:

    select * from student ...
    
    select * from teacher where tid=?
    select * from teacher where tid=?
    select * from teacher where tid=?
      ...

    查看sql发现,查了一条student语句,查了N条与stu关联的teacher语句。

    配置里面,除了配置lazy之外,还有个配置是fetch,fetch有2个选项:select和join。当fetch=join时,会不会只查一条语句呢?答案是:不会。原因(后续补...)

    所以,这里就出现了N+1的问题

    N+1问题:执行一条select语句查询当前表,执行N条语句查询与当前表关联的表,N是不同的关联数。效率很差
      lazy:是否及时加载,false是及时加载
      fetch:以什么样的方式加载,select(默认):select语句查询;join:以join语句查询
    注意:join在many-to-one中是无效的,在one-to-many中有效。
      A表===关联===>B表===关联===>C表...(关系多的话要一个表一个表的关联...)


    所以,在任何情况下,都不要在xml中配置lazy="false" fetch="join"


    N+1解决方案:
    自己写hql语句,如加入 hql = "from Stu s left join fetch s.teacher where s.sex = :sex",
      left join代表左外连接,fetch代表把查出来的s.teacher抓取到Category对象中。

      如果不写fetch,则executeQuery这条hql语句,会得到一个对象数组 [Student[id,name,sex...] ,Teacher[id,name,...] ]  (可以自己debug查看执行结果)

    对应的sql语句如下:

    select s.* , t.*
      from 
    student s left outer join teacher t 
      on s.tid=t.id 
      where s.sex = ''

    如果不写hql,而又配置了many-to-one,则默认为懒加载关联,lazy="true",抛异常:
      org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    因为session在加载Stu后关闭,再去加载对应的关联teacher的时候,session已经关闭了。

    逃避不一定躲得过,面对不一定最难过
  • 相关阅读:
    ES进阶--01
    JVM--02
    JVM--01
    ES--08
    ES--07
    ES--06
    python实现当前主机ip 主机名称的获取
    djang中的blank=True 和null = True的区别
    python中yield的用法详解
    python 编写古诗赤壁赋
  • 原文地址:https://www.cnblogs.com/yangzhenlong/p/5077392.html
Copyright © 2011-2022 走看看