懒加载和抓取策略

hibernate中性能的指标:发出sql语句的数量
我们来讨论一下hibernate的性能问题,能提升hibernate的性能的方式有:
1、懒加载
2、抓取策略
3、hql语句
4、查询缓存
我们先来说一下懒加载:
hibernate的懒加载是针对类、集合、多对一单向关联什么时候发出SQL语句的技术。
我们通过例子来说明:

在这里我们讨论集合的懒加载

public void testLoad(){
        Session session=sessionFactory.openSession();
        Classes classes=(Classes) session.load(Classes.class, 1L);
        Set<Student> students=classes.getStudents();
        for(Student student:students){
            System.out.println(student);
        }
        session.close();
    }

我们在classes.getStudents()这一行设置断点,然后debug
这里写图片描述
在右上角的属性中,classes是一个代理类,并不是classes类本身。
在执行完classes.getStudents()这一行的时候,并没有立刻发出sql语句,在控制台的那句sql语句,是session.load()发出的。
当执行下一步的时候,即便里students集合,发出了sql语句
这里写图片描述
这说明,只有当我们查询该集合里面的内容时,才发出sql语句。

当集合映射文件的lazy=”extra”时,发出的sql语句更加精确
这个是lazy为默认值的情况
这里写图片描述

这个是lazy为extra的情况
这里写图片描述

抓取策略:在企业中,抓取策略通常跟懒加载一起使用,来提高hibernate的性能,一个控制发出sql的时机(懒加载),一个控制发出sql的数量(抓取策略)。
问题引入:经典的n+1语句问题

public void testClassicProblem(){
        Session session=sessionFactory.openSession();
        List<Classes> classess=session.createQuery("from Classes").list();
        for(Classes classes:classess){
            for(Student student:classes.getStudents())
            {
                System.out.println(student.getSname());
            }
        }
        session.close();
    }

在classes.hbm.xml文件中,fecth为默认值即select。
发出sql语句为:
这里写图片描述

n+1是什么意思呢? 因为在这里我们首先便利的是classes表,那么n就是指classes这个表里面有多少条记录。+1的意思是:这一条是查询classes中的所有记录,然后剩下的每条记录都要查询自己的记录

如果我们要查询一个表里面有一万个学生记录的话,那就要发出10001条sql语句,效率太低了。

所以这时候,引进了抓取策略。
设置抓取策略的属性是在映射文件中set属性里面。在抓取策略中,我们只研究一对多和多对多的情况。因为多对一和一对一的话,不管怎样抓取,就拿一条记录,影响不大。

<set name="students" lazy="extra" fetch="select">
            <key column="cid"></key>
            <one-to-many class="cn.ansel.domain.Student"/>
        </set>

fetch的取值为:select(默认)/join/subselect.
select:就是默认情况。
join:左外连接,查询所有记录
subselect:子查询,查询指定的记录

当我们使用fetch=”join“的策略来运行含有子查询的语句时:

Hibernate: select classes0_.cid as cid0_, classes0_.cname as cname0_, classes0_.cdescription as cdescrip3_0_ from Classes classes0_
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sdescription as sdescrip3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=?
under taker
jeff hardy
ansel
andy
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sdescription as sdescrip3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=?
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sdescription as sdescrip3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=?

并没有发出左外连接语句,所以,当需求分析出有子查询的sql语句的时候,用join抓取策略无效。
当需求分析中不包含子查询的sql时,join有效,这时候,懒加载的值laze=”true/false”已经没有意义了,因为左外连接就是查询所有记录。

对于上面的n+1情况,经过分析,是适合用子查询来操作的,那么我们把fetch的值改成subselect测试:

Hibernate: select classes0_.cid as cid0_, classes0_.cname as cname0_, classes0_.cdescription as cdescrip3_0_ from Classes classes0_
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.sdescription as sdescrip3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid in (select classes0_.cid from Classes classes0_)

如上所示,只发出了两条语句,一条查找所有课程,另外一条利用子查询,得到找到课程的id作为条件,再查询里面的学生。

我们在使用subselect抓取策略的时候,lazy的取值是起作用的,当lazy为真/extra的时候,当我们遍历/获取里面的属性的时候,才发出sql语句。
当lazy=false的时候,在我们得到集合的时候就发出sql语句

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值