hibernate缓存机制(一)-n+1问题

      hibernate缓存包括一级缓存(session级别)、二级缓存(sessionFactory级别)和查询缓存(sessionFactory级别)。

在分析缓存之前,先来看看hibernate的n+1问题。

1、什么是N+1问题

list()获得对象:

/**

             * 此时会发出一条sql,将30个学生全部查询出来

             */

            List<Student> ls = (List<Student>)session.createQuery("from Student")

                                .setFirstResult(0).setMaxResults(30).list();

            Iterator<Student> stus = ls.iterator();

            for(;stus.hasNext();)

            {

                Student stu = (Student)stus.next();

                System.out.println(stu.getName());

            }

如果通过list()方法来获得对象,毫无疑问,hibernate会发出一条sql语句,将所有的对象查询出来,这点相信大家都能理解

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.rid as rid2_, student0_.sex as sex2_ from t_student student0_ limit ?

那么,我们再来看看iterator()这种情况

iterator()获得对象

/**

             * 如果使用iterator方法返回列表,对于hibernate而言,它仅仅只是发出取id列表的sql

             * 在查询相应的具体的某个学生信息时,会发出相应的SQL去取学生信息

             * 这就是典型的N+1问题

             * 存在iterator的原因是,有可能会在一个session中查询两次数据,如果使用list每一次都会把所有的对象查询上来

             * 而使用iterator仅仅只会查询id,此时所有的对象已经存储在一级缓存(session的缓存)中,可以直接获取

             */

            Iterator<Student> stus = (Iterator<Student>)session.createQuery("from Student")

                                .setFirstResult(0).setMaxResults(30).iterate();

            for(;stus.hasNext();)

            {

                Student stu = (Student)stus.next();

                System.out.println(stu.getName());

            }

在执行完上述的测试用例后,我们来看看控制台的输出,看会发出多少条 sql 语句:

Hibernate: select student0_.id as col_0_0_ from t_student student0_ limit ?

Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0_.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where student0_.id=?

沈凡

Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0_.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where student0_.id=?

王志名

Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0_.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where student0_.id=?

叶敦

.........

   我们看到,当如果通过iterator()方法来获得我们对象的时候,hibernate首先会发出1sql去查询出所有对象的 id 值,当我们如果需要查询到某个对象的具体信息的时候,hibernate此时会根据查询出来的 id值再发sql语句去从数据库中查询对象的信息,这就是典型的N+1的问题

   那么这种 N+1 问题我们如何解决呢,其实我们只需要使用 list() 方法来获得对象即可。但是既然可以通过 list() 我们就不会出现 N+1的问题,那么我们为什么还要保留 iterator()这种形式呢?我们考虑这样一种情况,如果我们需要在一个session当中要两次查询出很多对象,此时我们如果写两条 list()时,hibernate此时会发出两条 sql 语句,而且这两条语句是一样的。但是我们如果第一条语句使用 list(),而第二条语句使用 iterator()的话,此时我们也会发两条sql语句,但是第二条语句只会将查询出对象的id,所以相对应取出所有的对象而已,显然这样可以节省内存,而如果再要获取对象的时候,因为第一条语句已经将对象都查询出来了,此时会将对象保存到session的一级缓存中去,所以再次查询时,就会首先去缓存中查找,如果找到,则不发sql语句了。

这里就牵涉到了接下来这个概念:hibernate的一级缓存。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值