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