时间: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. Java安全之XStream 漏洞分析

    Java安全之XStream 漏洞分析 0x00 前言 好久没写漏洞分析文章了,最近感觉在审代码的时候,XStream 组件出现的频率比较高,借此来学习一波XStream的漏洞分析. 0x01 XSt ...

  2. Java的代理模式

    最近在学习Spring,关于Spring AOP的代理模式不是很了解,看了一篇博文就懂了. https://www.cnblogs.com/cenyu/p/6289209.html Java的三种代理 ...

  3. 【技巧】使用PPT更换背景色

    主要记述使用PPT来更换图片某一部分的背景色 把想要更改的图片粘贴到PPT里. 依次选择[格式][颜色][设置透明色],然后点击需要更改背景的地方 将自己的目标颜色复制一下,填充上去,选择[置于底层]

  4. 痞子衡嵌入式:嵌入式Cortex-M裸机环境下临界区保护的三种实现

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Cortex-M裸机环境下临界区保护的三种实现. 搞嵌入式玩过 RTOS 的朋友想必都对 OS_ENTER_CRITICAL().OS_ ...

  5. python框架之Flask

    介绍:Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 . WSGl:Web Server Gateway ...

  6. IntelliJ IDEA2021.2 常用快捷键汇总总结

    Java开发环境:Windows10 64bit+JDK8+IDEA2021.2 =========================================================== ...

  7. 'utf-8' codec can't decode byte的解决办法

    参考链接:https://www.cnblogs.com/zyh19980816/p/11830065.html 问题:''utf-8' codec can't decode byte 0xa3 in ...

  8. vi正则表达式

    搜索命令:/正则表达式 替换命令::s/正则表达式/替换字符串/选项 :%s/str1/str2/g   该命令中:表示进入命令行模式,%表示对该文件所有行有效,s表示查找并替换,正则表达式str1表 ...

  9. 🔥 LeetCode 热题 HOT 100(11-20)

    20. 有效的括号 class Solution { public boolean isValid(String s) { Map<Character, Character> map = ...

  10. 关于win7+cenos 7双系统安装

    ---恢复内容开始--- 1,cenos 0 7制作U盘启动 制作工具 http://pan.baidu.com/s/1nv9lpmp 镜像自备 2,安装centos 7 释放磁盘空间,如:20G.用 ...