时间:2017-1-23 19:08

——区分延迟和立即检索

1、立即检索
    当执行某行代码时,会马上发出SQL语句进行查询。
    例如:get()

2、延迟检索
    当执行某行代码时,不会马上发出SQL语句,只有当真正使用对象时,才会向数据库发出SQL语句。
    例如:load()

3、示例代码
    /*

     * 区分立即检索和延迟检索
     */
    public void fun1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
 
        // 立即检索
        Customer customer = (Customer) session.get(Customer.class, 1);
        System.out.println(customer);
 
        /*
         * 延迟检索
         * 当持久化类设置为final之后,延迟检索就失效了,因为不能生成代理对象
         * 在Customer.hbm.xml的<class>标签上配置lazy="false",表示不支持延迟检索
         */
        Customer customer2 = (Customer) session.load(Customer.class, 1);
        // 初始化代理对象
        System.out.println(customer2);
        Hibernate.initialize(customer2); // 会立即检索
 
 
        tx.commit();
        session.close();
    }

——类级别检索和关联级别检索

1、类级别的检索:
    1)类级别可选的检索策略包括立即检索和延迟检索,默认为延迟检索。
    2)类级别的检索策略可以通过<class>元素的lazy属性进行设置。
    3)如果程序加载一个对象的目的是为了访问它的属性,可以采取立即检索的方式,如果程序加载一个持久化对象的目的仅仅是为了获得它的引用,可以采用延迟检索。
    4)无论<class>元素的lazy属性是true还是false,Session的get()方法以及Query的list()方法在类级别总是使用立即检索的策略。
    5)若<class>元素的lazy属性为true或取默认值,Session的load()方法不会执行查询数据表的select语句,而是仅返回代理对象的实例,该代理对象实例有如下特征:
        *   由Hibernate在运行时采用javassist工具动态生成
        *   Hibernate创建代理对象实例时,仅初始化其OID属性
        *   在应用程序第一次访问代理实例的非OID属性时,Hibernate会初始化代理类实例。

2、关联级别的检索
    1)在映射文件中,用<set>元素来配置一对多关联及多对多关联关系,<set>元素中有lazy和fetch属性:
    2)lazy:主要决定orders集合被初始化的时机,即是否在Customer对象初始化时被加载,还是在程序访问orders集合时被初始化。
    3)fetch:取值为select或subselect时,决定初始化orders的查询语句的形式,若取值为join,则决定orders集合被初始化的时机。
    4)若把fetch设置为“join”,lazy属性将被忽略。

——一方关联多方的情况

    在<set>元素中包含fetch和lazy属性:
        *   fetch:控制SQL语句的类型
            >   join:采用迫切左外连接查询
            >   select:默认值
            >   subselect:发送子查询来查询关联对象

        *   lazy:控制关联对象的检索是否采用延迟
            >   true:默认值,查询关联对象采用延迟检索
            >   false:查询关联对象不使用延迟检索
            >   extra:特懒

    join:一次查完
    select:分多次查完

    lazy="true":延迟查询
    lazy="false":不延迟查询

    如果fetch="join",那么lazy属性将被忽略。

示例代码:
    1)<set>集合中没有配置fetch和lazy的情况
        默认值:fetch="select" lazy="true"

        // 只发送查询客户的SQL语句,没有发送查询订单的SQL

        Customer customer = (Customer) session.get(Customer.class, 1);
        // 使用客户订单信息的时候,才会发送查询订单的SQL语句
        System.out.println(customer.getOrders().size());

SQL:

            Hibernate: 
                select
                    customer0_.cid as cid0_0_,
                    customer0_.cname as cname0_0_ 
                from
                    customer customer0_ 
                where
                    customer0_.cid=?
 
            Hibernate: 
                select
                    orders0_.cid as cid0_1_,
                    orders0_.oid as oid1_,
                    orders0_.oid as oid1_0_,
                    orders0_.addr as addr1_0_,
                    orders0_.cid as cid1_0_ 
                from
                    order_table orders0_ 
                where
                    orders0_.cid=?

2)在<set>标签中配置fetch="join",lazy会被忽略

            * 只要fetch设置为join,会采用迫切左外连接进行查询
        // 直接发送一条迫切左外连接查询,查询全部数据,包括订单信息
        Customer customer = (Customer) session.get(Customer.class, 1);
        System.out.println(customer.getOrders().size());

SQL:
            Hibernate:

                select
                    customer0_.cid as cid0_1_,
                    customer0_.cname as cname0_1_,
                    orders1_.cid as cid0_3_,
                    orders1_.oid as oid3_,
                    orders1_.oid as oid1_0_,
                    orders1_.addr as addr1_0_,
                    orders1_.cid as cid1_0_ 
                from
                    customer customer0_ 
                left outer join
                    order_table orders1_ 
                        on customer0_.cid=orders1_.cid 
                where
                    customer0_.cid=?

3)在<set>标签中配置fetch="select" lazy="extra"

            * lazy="extra" 极其懒惰
        // 只查询Customer的信息,不查询关联对象信息
        Customer customer = (Customer) session.get(Customer.class, 1);
        // 当查询数量时,只会发送:select count(*) from order_table where oid = ?
        System.out.println(customer.getOrders().size());
        // 当查询订单时,才会查询全部订单信息:selecg * from order_table
        System.out.println(customer.getOrders());

SQL:
            Hibernate:

                select
                    customer0_.cid as cid0_0_,
                    customer0_.cname as cname0_0_ 
                from
                    customer customer0_ 
                where
                    customer0_.cid=?

            Hibernate: 
                select
                    count(oid) 
                from
                    order_table 
                where
                    cid =?
 
            Hibernate: 
                select
                    orders0_.cid as cid0_1_,
                    orders0_.oid as oid1_,
                    orders0_.oid as oid1_0_,
                    orders0_.addr as addr1_0_,
                    orders0_.cid as cid1_0_ 
                from
                    order_table orders0_ 
                where
                    orders0_.cid=?

4)在<set>标签中配置fetch="subselect" lazy="true"

            * 使用subselect的时候需要使用Query接口进行测试,因为需要查询多个客户,才能看到子查询的效果
            * 查询一个客户和查询多个客户有什么区别?
    *   > 如果只有一个客户会使用:=
    *   > 如果有多个客户会使用:in
 
        List<Customer> list = session.createQuery("from Customer").list();
        for(Customer c : list){
            System.out.println(c.getOrders().size());
        }

SQL:
            Hibernate:

                select
                    customer0_.cid as cid0_,
                    customer0_.cname as cname0_ 
                from
                    customer customer0_
            Hibernate: 
                select
                    orders0_.cid as cid0_1_,
                    orders0_.oid as oid1_,
                    orders0_.oid as oid1_0_,
                    orders0_.addr as addr1_0_,
                    orders0_.cid as cid1_0_ 
                from
                    order_table orders0_ 
                where
                    orders0_.cid in (
                        select
                            customer0_.cid 
                        from
                            customer customer0_
                    )

——多方关联一方的情况

1、多对一和一对一关联的检索策略,和<set>一样,<many-to-one>元素也有一个lazy属性和fetch属性:
    *   若fetch属性设为join,那么lazy属性被忽略。
    *   迫切左外连接检索策略的优点在于比立即检索策略使用的select语句更少。
    *   无代理延迟检索需要增强持久化类的字节码才能实现。

2、Query的list()方法会忽略映射文件配置的迫切左外连接检索策略,而采用延迟检索或立即检索策略,根据Customer类级别的lazy属性进行检索,lazy="true"为延迟检索,lazy="false"为立即检索。

3、如果在关联级别使用了延迟加载或立即加载检索策略,可以设定批量检索的大小,以帮助提高延迟检索或立即检索的运行性能。

4、<many-to-one>
    *   fetch:控制SQL语句发送格式
        >   join:使用迫切左外连接查询,lazy会被忽略
        >   select:发送多条SQL检索对象
    *   lazy:关联对象检索的时候,是否采用延迟
        >   false:不延迟
        >   proxy:使用代理,检索订单时是否马上检索客户,由Customer对象的映射文件中<class>元素的lazy属性来决定
        >   no-proxy:不使用代理

示例代码:
    1)没有在<many-to-one>标签上进行配置

            * 发送多条SQL来查询订单中的信息

// 只查询订单的记录,拿到的是关联Customer的引用

        Order order = (Order) session.get(Order.class, 1);
        // 使用订单的Customer对象时,会发送一条SQL查询订单关联的客户对象的信息
        System.out.println(order.getCustomer().getCname());

SQL:
            Hibernate:

                select
                    order0_.oid as oid1_0_,
                    order0_.addr as addr1_0_,
                    order0_.cid as cid1_0_ 
                from
                    order_table order0_ 
                where
                    order0_.oid=?
            Hibernate: 
                select
                    customer0_.cid as cid0_0_,
                    customer0_.cname as cname0_0_ 
                from
                    customer customer0_ 
                where
                    customer0_.cid=?

2)在<many-to-one>标签上进行配置

            * fetch="join" lazy会被忽略
            * 发送迫切左外连接 

// 发送一条迫切左外连接,将全部信息都获取到,并且封装到对象中

        Order order = (Order) session.get(Order.class, 1);
        System.out.println(order.getCustomer().getCname());
 

SQL:
            Hibernate:

                select
                    order0_.oid as oid1_1_,
                    order0_.addr as addr1_1_,
                    order0_.cid as cid1_1_,
                    customer1_.cid as cid0_0_,
                    customer1_.cname as cname0_0_ 
                from
                    order_table order0_ 
                left outer join
                    customer customer1_ 
                  ·  on order0_.cid=customer1_.cid 
                where
                    order0_.oid=?

3)在<many-to-one>标签上设置
            * fetch="select" lazy="false"

        // 发送多条SQL,不延迟,一次查完
        Order order = (Order) session.get(Order.class, 1);
        System.out.println(order.getCustomer().getCname());

SQL:
            Hibernate:

                select
                    order0_.oid as oid1_0_,
                    order0_.addr as addr1_0_,
                    order0_.cid as cid1_0_ 
                from
                    order_table order0_ 
                where
                    order0_.oid=?
            Hibernate: 
                select
                    customer0_.cid as cid0_0_,
                    customer0_.cname as cname0_0_ 
                from
                    customer customer0_ 
                where
                    customer0_.cid=?

——批量抓取

1、从一方批量抓取多方记录

    在Customer.hbm.xml的<set>标签上配置batch-size="2"
        * 表示一次查询两个

示例代码:
    List<Customer> list = session.createQuery("from Customer").list();

        for(Customer customer : list){
            for(Order order : customer.getOrders()){
                System.out.println(order.getAddr());
            }
        }

SQL:

    Hibernate: 
        select
            customer0_.cid as cid0_,
            customer0_.cname as cname0_ 
        from
            customer customer0_
    Hibernate: 
        select
            orders0_.cid as cid0_1_,
            orders0_.oid as oid1_,
            orders0_.oid as oid1_0_,
            orders0_.addr as addr1_0_,
            orders0_.cid as cid1_0_ 
        from
            order_table orders0_ 
        where
            orders0_.cid in (
                ?, ?
            )
    奎文3
    奎文4
    奎文1
    奎文7
    奎文2
    奎文0
    奎文8
    奎文6
    奎文9
    奎文5
    高新2
    高新9
    高新3
    高新8
    高新1
    高新4
    高新0
    高新5
    高新6
    高新7
    Hibernate: 
        select
            orders0_.cid as cid0_1_,
            orders0_.oid as oid1_,
            orders0_.oid as oid1_0_,
            orders0_.addr as addr1_0_,
            orders0_.cid as cid1_0_ 
        from
            order_table orders0_ 
        where
            orders0_.cid=?
    潍城4
    潍城5
    潍城6
    潍城1
    潍城7
    潍城0
    潍城9
    潍城2
    潍城3
    潍城8

2、从多方批量抓取一方记录
    不能在多方设置batch-size属性,需要在一方的<class>标签上设置batch-size。

——总结

1、立即检索

2、延迟检索
    配置fetch和lazy属性
    *   配置立即检索
        >   lazy="false"
        >   持久化类设置为final
        >   在调用方法的时候,初始化代理对象
3、延迟
    类级别的延迟:
        <class>元素上设置lazy

    关联级别的延迟:
        <set> / <many-to-many> / <one-to-one>

4、fetch属性
    *   <set>集合上的fetch:
        >   join:强制使用迫切左外连接
        >   select:默认值,会发送多条SQL语句
        >   subselect:使用子查询
    *   在<many-to-one>标签上使用
        >   select:默认值,发送多条SQL
        >   join:强制使用迫切左外连接

5、lazy属性
    *   <set>
        >   true:默认值,延迟
        >   false:不采用延迟
        >   extra:极其懒惰
    *   <many-to-one>
        >   proxy:根据另一方的<calss>元素配置的lazy来确定是否使用延迟。
        >   false:不采用延迟。
        >   no-proxy

6、batch-size批量抓取
    默认情况下只会检索一条记录,如果想要批量抓取多条记录,可以使用batch-size进行检索。

Hibernate之抓取策略的更多相关文章

  1. Hibernate的抓取策略(优化)

    延迟加载的概述 什么是延迟加载 延迟加载:lazy(懒加载).执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询. 延迟加载的分类 l  类级别的延 ...

  2. 八 Hibernate延迟加载&抓取策略(优化)

    面试:Hibernate效率很低,如何优化? 缓存怎么弄的,语句怎么优化? 聊聊一级缓存,聊聊抓取策略和延迟加载,聊聊批量抓取 延迟加载: 一般不单独使用,和延迟加载一起使用 延迟加载:lazy(懒加 ...

  3. Hibernate的抓取策略

    立即检索:当执行某行代码的时候,马上发出SQL语句进行查询(get())延迟检索:当执行某行代码的时候,不会马上发出SQL语句进行查询.当真正使用这个对象的时候才会发送SQL语句(load()) 类级 ...

  4. 【Hibernate】抓取策略

    一.区分延迟和立即检索 二.类级别检索和关联级别检索 一.区分延迟和立即检索 立即检索: 当执行某行代码的时候,马上发出SQL语句进行查询. get() 延迟检索: 当执行某行代码的时候,不会马上发出 ...

  5. 【Hibernate 8】Hibernate的调优方法:抓取策略

    在上一篇博客中,介绍了Hibernate的缓存机制.合理的配置缓存,可以极大程度上优化Hibernate的性能.这篇博客,介绍另外一个调优方式:抓取策略. 一.什么是抓取策略 抓取策略(fetchin ...

  6. Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制

    目录 1. Hibernate的查询方式 1.1 方式一:OID查询 1.2 方式二:对象导航查询 1.3 方式三:HQL方式 1.4 方式四:QBC查询 1.5 方式五:SQL查询 2. 环境搭建 ...

  7. Hibernate(十四)抓取策略

    抓取策略: 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.Hibernate的抓取策略是Hibernate提升性能的一 ...

  8. Hibernate 抓取策略

    抓取策略: 为了改变SQL语句执行的方式 当应用程序需要在Hibernate实体对象的关联关系间进行导航的时候,Hibernate如何获取关联对象的策略 抓取策略可以在O/R映射的元数据中声明,也可以 ...

  9. day36 08-Hibernate抓取策略:批量抓取

    package cn.itcast.test; import java.util.List; import org.hibernate.Hibernate; import org.hibernate. ...

随机推荐

  1. python 实现自动部署测试环境

    预设条件 产品运行在Linux CentOS6 X64上 python3,Djanggo,Cherrypy安装好手动安装过程 登录服务器 检查是否有以前的版本的产品在运行,有,停掉 如果有原来的代码包 ...

  2. Visual Studio2019下载最新离线安装包

    首先可以参考微软官方的离线安装说明-->点击这里打开 =================================================================== 1. ...

  3. 第十四篇 -- CPU学习二——此部分重点在AMD CPU

    一.CPU的一些英文简写或解释 Definitions: ACPI--Advanced Configuration and Power Interface APP--Adjusted Peak Per ...

  4. edraw mindmaster pro 8.1.0安装破解教程

    Edraw MindMaster Pro 8.1.0是一款思维导图(脑图)设计软件,头脑风暴.思维整理.项目策划.团队协作,多场景提升您的效率,功能齐全,个人觉得比xmind好用上手,文章手把手教你安 ...

  5. atom之插件安装及相关

    1. simplified-chinese-menu 汉化软件 2. file-icons 加上文件图标 3. language-vue 加上vue语言支持 4. platformio-ide-ter ...

  6. 移动APP我们需要关注什么

    移动APP关注的点比web或者PC上的程序更多 1.测试用例的设计 移动互联网的快节奏,要放弃传统的测试用例编写方式,不需要写详细的测试用例,采用罗列测试点的方式如思维导图,这样既节省时间又能够直观清 ...

  7. Netty 源码分析系列(二)Netty 架构设计

    前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...

  8. 【算法学习笔记】动态规划与数据结构的结合,在树上做DP

    前置芝士:Here 本文是基于 OI wiki 上的文章加以修改完成,感谢社区的转载支持和其他方面的支持 树形 DP,即在树上进行的 DP.由于树固有的递归性质,树形 DP 一般都是递归进行的. 基础 ...

  9. Java 反射(二)运行时获取类的信息

    目录 一.获得类的运行时结构 1. 获得类的名字 2. 获得类的属性 获取属性列表 获取指定属性 3. 获取类的方法 获得类的方法列表 获得指定方法 4. 获得的构造器 获得构造器列表 获得指定构造器 ...

  10. Python中input()函数用法

    input()函数获取用户输入数据,实现用户交互 语法格式: 变量 = input("提示信息") input()返回的是字符串,无论输入的是数字还是字符串,默认的输入结束键是回车 ...