hibernate的抓取策略

一、hibernate抓取策略概述


    Hibernate抓取策略(fetching strategy)是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明。
    需要注意的是:hibernate的抓取策略只影响get load 方法,对hql是不影响的。    


二、hibernate 抓取策略分类     


    hibernate有如下四种原生态的Hibernate抓取策略,分别是:select fetching ,join fetching,subselect fetching,Batch fetching。

接下来,我们来详细看一下每种策略的实现

    1、查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
    代码如下:    

       

<span style="font-family:KaiTi_GB2312;font-size:18px;"> Student student = (Student)session.get(Student.class, 1);
    System.out.println(student.getName());
    System.out.println(student.getClasses().getName());</span>
 

   配置如下:
        <many-to-one name="classes" column="classesid" fetch="select"/>


    执行结果:2条语句


    Hibernate: select student0_.id as id1_0_, student0_.name as name1_0_, student0_.class_id as class3_1_0_ from student_join student0_ where student0_.id=?
    学生1
    Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes_join classes0_ where classes0_.id=?
    高一(1)班    
    
    2、连接抓取(Join fetching) 

    Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来 获得对象的关联实例或者关联集合。
    

    配置如下:        

<many-to-one name="classes" column="classesid" fetch="join"/>

 

    执行结果:
        fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合,      
        此时lazy会失效,    
        一条join语句:
        
        Hibernate: select student0_.id as id1_1_, student0_.name as name1_1_, student0_.class_id as class3_1_1_, classes1_.id as id0_0_, classes1_.name as name0_0_ from student_join student0_ left outer join classes_join classes1_ on student0_.class_id=classes1_.id where student0_.id=?
        学生1
        高一(1)班
        
    如果在配置中在添加一个非空属性,连接就成内连接了:

    

    3、子查询抓取(Subselect fetching)

     另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
    配置文件:
        <set name="students" inverse="true" fetch="subselect">
        fetch="subselect",另外发送一条select语句抓取在前面查询到的所有实体对象的关联集合。
        访问代码如下:      

   

     <span style="font-family:KaiTi_GB2312;font-size:18px;"> List classList = session.createQuery("from Classes where id in (1,2,3)").list();
            for(Iterator iter = classList.iterator(); iter.hasNext();){
                Classes c = (Classes)iter.next();
                System.out.println("Class.name=" + c.getName());
                Set stuSet = c.getStudents();
                System.out.println(stuSet.size());
                if(stuSet != null && !stuSet.isEmpty()){
                   for(Iterator it = stuSet.iterator(); it.hasNext();){
                      Student s = (Student) it.next();
                      System.out.println("student.name=" + s.getName());
                   }
                }</span>
            }


    
     执行结果:
        当不设fetch="subselect" ,即:<set name="students" inverse="true">,结果如下:
        执行了3条查询语句
        Hibernate: select classes0_.id as id0_, classes0_.name as name0_ from classes_join classes0_  where classes0_.id in (1 , 2 , 3)
        Class.name=高一(1)班
        Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student_join students0_ where students0_.class_id=?
        3
        student.name=学生4
        student.name=学生6
        student.name=学生2
        Class.name=高一(2)班
        Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student_join students0_ where students0_.class_id=?
        4
        student.name=学生3
        student.name=学生4
        student.name=学生1
        student.name=学生2
        Class.name=高一(3)班
        Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student_join students0_ where students0_.class_id=?
        0
        
        当设fetch="subselect" ,即:<set name="students" inverse="true" fetch="subselect">,结果如下:
        执行了1条查询语句(嵌套子查询)
        Hibernate: select classes0_.id as id0_, classes0_.name as name0_ from classes_join classes0_ where classes0_.id in (1 , 2 , 3)
        Class.name=高一(1)班
        Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student_join students0_ where students0_.class_id in (select classes0_.id from classes_join classes0_ where classes0_.id in (1 , 2 , 3))
        
        


    4、批量抓取(Batch fetching)

     对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句获取一批对象实例或集合。如果我们不使用hibernate的抓取策略,那么代码如下:

     


    

   但是可以发现这里有一个问题就是“N+1”问题。我们会发出N多条sql语句,怎么解决问题呢?
        

       在 class 上使用batch-size


        batch-size属性,可以批量加载实体类。<class name="Classes" table="t_classes" batch-size="3">
        当查classes对象时发出9条hql语句配置过后batch-size=3后会之发9/3=3条hql语句,提高性能。
        具体效果如下:

       

       

        在集合上使用
                以上是在class上使用,batch-size还可以在集合上使用:batch-size属性,可以批量加载实体类,<set name="students" inverse="true" cascade="all" batch-size="5">
        当查students对象时发出10条hql语句配置过后batch-size=5后会之发10/5=2条hql语句,提高性能
            
    

三、总结
    
        四种抓取策略说明完了, 咱们来宏观一下, 通过例子可以看出, 这四种抓取策略并不是所有的情况都合适的, 例如, 如果我需要初始化的是一个单独的实体, 那么 subselect 对其就没有效果,因为其本身就只需要查询一个对象, 所以 我们可以对hibernate分成如下两类:单端代理抓取和集合抓取。
    
        单端代理抓取可以使用:Join fetching , Select fetching 与 Batch-size ,可以为单个实体的抓取进    行性能优化;
       集合抓取: Join fetching , Select fetching ,Subselect fetching , Batch fetching,可以为集合的抓取进行性能优化;

原文:https://blog.csdn.net/wangyongxia921/article/details/43973287 
 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值