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已经关闭了。

posted @ 2015-12-26 02:01  艺言弈行  阅读(1215)  评论(0编辑  收藏  举报