【极客营】Hibernate查询之HQL查询-对查询功能优化

作者:何征天

课程视频地址:https://ke.qq.com/course/273907

1.1.   需求分析

1. 对Hibernate框架的查询进行优化

1.2.   技术分析之延迟加载(重要)

1. 延迟加载先获取到代理对象,当真正使用到该对象中的属性的时候,才会发送SQL语句,是Hibernate框架提升性能的方式

 2.类级别的延迟加载
        * Session对象的load方法默认就是延迟加载
        * Customer c = session.load(Customer.class, 1L);没有发送SQL语句,当使用该对象的属性时,才发送SQL语句
        
        * 使类级别的延迟加载失效
          * 标签上配置lazy=”false”
          * Hibernate.initialize(Objectproxy);

【准备工作】

【示例】

     1.在com.igeek.demo4下新建Demo1类,代码如下:

packagecom.igeek.demo4;

 

import org.hibernate.Session;

import org.hibernate.Transaction;

import org.junit.Test;

 

import cn.igeekutil.HibernateUtils;

 

publicclass Demo1 {

    /**

     * 延迟加载概念:没有真正发生sql语句,查看该对象中属性值的时候,才会发生sql

     */

    @Test

    publicvoid run1(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //1号客户,默认使用延迟加载

       //设置断点

       Customer c = session.load(Customer.class, 1L);

       System.out.println(c.getCust_id());

       System.out.println("==================");

       //打印客户名称

       System.out.println(c.getCust_name());

       tr.commit();

    }

}

2.通过断点调试测试,在执行System.out.println(c.getCust_id());,打印了id值,但是没有发sql语句,在执行System.out.println(c.getCust_name());后才打印sql语句,说明hibernate框架在我们需要数据时才去数据库查询,这样可以提升程序性能,这是延迟加载的作用。

3.修改Customer.hbm.xml文件,标签上配置lazy=”false”,不使用延迟加载,当执行Customer c = session.load(Customer.class, 1L);后,控制台直接输出sql语句,说明没有使用延迟加载。

<class name="com.igeek.demo4.Customer" table="cst_customer" lazy="false">

【极客营】Hibernate查询之HQL查询-对查询功能优化_第1张图片

3. 关联级别的延迟加载(查询某个客户,当查看该客户下的所有联系人是是否是延迟加载)
      * 默认是延迟加载

  【示例】

     1.在Demo1类中添加测试代码:

//关联级别的延迟加载

    @Test

    publicvoid run2(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //1号客户,默认使用延迟加载

        //设置断点

       Customer c = session.get(Customer.class, 1L);

       System.out.println(c.getCust_id());

       System.out.println("====================");

       //打印客户关联的联系人数量

       System.out.println(c.getLinkmans().size());

       tr.commit();

}

 2.修改Customer.hbm.xml文件中lazy属性,然后通过断点测试

<class name="com.igeek.demo4.Customer" table="cst_customer" >

测试结果:执行Customer c = session.get(Customer.class, 1L);发送查询客户表的sql,执行System.out.println(c.getLinkmans().size());发送查询联系人的sql,说明hibernateget方法在查询关联表时,使用的是延迟加载。

1.3.   技术分析之Hibernate框架的查询策略

1.查询策略:使用Hibernate查询一个对象的时候,查询其关联对象.应该如何查询.是Hibernate的一种优化手段!!!    

2. Hibernate 框架的检索策略解决的问题
   * 查询的时机

      Customer c1 =(Customer) session.get(Customer.class, 1);

System.out.println(c1.getLinkmans().size());
            
   * lazy属性解决查询的时机的问题,需要配置是否采用延迟加载!!
        
   * 查询的语句形式
      Listlist = session.createQuery("from Customer").list();
        for(Customerc : list){
          System.out.println(c.getLinkmans());
         }
            
     * fetch属性就可以解决查询语句的形式的问题!!

1.4.   技术分析之在set标签上配置策略

1. 标签上使用fetch和lazy属性
    * fetch的取值        -- 控制SQL语句生成的格式
      * select         --默认值.发送查询语句
      * join          --连接查询.发送的是一条迫切左外连接!!!配置了join.lazy就失效了
      * subselect       --子查询.发送一条子查询查询其关联对象.(需要使用list()方法进行测试)
        
      * lazy的取值      -- 查找关联对象的时候是否采用延迟!
         * true      -- 默认.延迟
         * false       -- 不延迟
         * extra      --及其懒惰
    
  2. set标签上的默认值是fetch="select"和lazy="true"
  3. 总结:Hibernate框架都采用了默认值,开发中基本上使用的都是默认值。

【示例】

1.在Demo1类中添加测试代码:

//加载策略测试

    @Test

    publicvoid run3(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //1号客户,默认使用延迟加载

       //设置断点

       Customer c = session.get(Customer.class, 1L);

       System.out.println(c.getCust_id());

       System.out.println("====================");

       //打印客户关联的联系人数量

       System.out.println(c.getLinkmans().size());

       tr.commit();

    }

2.修改Customer.hbm.xml配置文件,使用断点测试,观察结果

       <set name="linkmans" fetch="select" lazy="true">

3.修改Customer.hbm.xml配置文件,把lazy属性设置为false,再次测试。

       <set name="linkmans" fetch="select" lazy="false">

4.修改Customer.hbm.xml配置文件,把lazy属性设置为extra,再次测试。

       <set name="linkmans" fetch="select" lazy="extra">

【极客营】Hibernate查询之HQL查询-对查询功能优化_第2张图片

5.修改Customer.hbm.xml配置文件,把fetch属性设置为join,再次测试,发现只打印了1条sql语句,原先是2条,优化了sql查询。lazy属性设置为false或true都一样,因为只发送一条sql语句。

       <set name="linkmans" fetch="join" lazy="true">

6.在Demo1类中添加测试方法,测试发现每查询一次客户就发送一条sql,显然不合理

//加载策略测试

    @Test

    publicvoid run4(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //查询所有客户

       //设置断点

       List customers = session.createQuery("from Customer").list();

        for (Customer customer : customers) {

           System.out.println(customer.getLinkmans().size());

       }

       tr.commit();

    }

7.修改Customer.hbm.xml配置文件,把fetch属性设置为subselect,再次测试,只发送2条sql语句,hibernate优化了查询。

       <set name="linkmans" fetch="subselect" lazy="true">

1.5.   技术分析之在many-to-one标签上配置策略

1. 标签上使用fetch和lazy属性
        * fetch的取值        -- 控制SQL的格式
            * select       --默认。发送基本select语句查询
            * join            --无效        
        * lazy的取值        -- 控制加载关联对象是否采用延迟
            * false      --不采用延迟加载
            * proxy       --默认值.代理.现在是否采用延迟
                   * 由另一端的上的lazy确定.如果这端的set上的lazy=”true”.proxy的值就是true(延迟加载)
                * 如果set上lazy=”false”.proxy的值就是false(不采用延迟)
    
    2. 标签上的默认值是fetch="select"和proxy

【示例】

1.在Demo1类中添加测试代码:

//多方配置加载策略

    @Test

    publicvoid run5(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //1号客户,默认使用延迟加载

       Customer c = session.get(Customer.class, 1L);

       System.out.println(c.getCust_id());

       System.out.println("====================");

       //打印客户关联的联系人数量

       System.out.println(c.getLinkmans().size());

       tr.commit();

    }

2.修改Customer.hbm.xml

<set name="linkmans"  lazy="true">

3.修改Linkman.hbm.xml

       <many-to-one fetch="select" lazy="proxy"   name="Customer" class="com.igeek.demo4.Customer" column="lkm_cust_id">many-to-one>

4.把Customer.hbm.xml中的lazy改成 true 和false 分别测试,查看结果。

1.6.   批量抓取(了解)

1. 获取客户下的联系人的信息

在Demo2中添加测试方法   

//批量抓取,能简化生成的SQL语句

    @Test

    publicvoid run6(){

       Session session = HibernateUtils.getCurrentSession();

       Transaction tr = session.beginTransaction();

       //查询所有客户

       //设置断点

       List customers = session.createQuery("from Customer").list();

       for (Customer customer : customers) {

           for (Linkman linkman : customer.getLinkmans()) {

              System.out.println(linkman);

           }

       }

       tr.commit();

    }

在Linkman类中添加toString()方法,方便打印

@Override

    public String toString() {

       return"Linkman [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + ", lkm_cust_id=" + lkm_cust_id + ", lkm_gender="

              + lkm_gender + ", lkm_phone=" + lkm_phone + ", lkm_mobile=" + lkm_mobile + ", lkm_email=" + lkm_email

              + ", lkm_qq=" + lkm_qq + ", lkm_position=" + lkm_position + ", lkm_memo=" + lkm_memo + ", customer="

              + customer + "]";

    }

会发生多条SQL语句
    
    2. 可以在标签上配置batch-size属性,设置批量抓取,这样可以减少SQL语句的发送。

<set name="linkmans"  batch-size="10">

【极客营】Hibernate查询之HQL查询-对查询功能优化_第3张图片




你可能感兴趣的:(【极客营】Hibernate查询之HQL查询-对查询功能优化)