zoukankan      html  css  js  c++  java
  • Hibernate之抓取策略

    时间: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进行检索。

  • 相关阅读:
    让UILabel的大小自适应字符串长度
    Cocos2dx中的分辨率学习
    关键帧动画-五角星动画-在层上画出五角星
    .net WINFORM 界面怎么做凹凸效果的分割线?就是横线
    游标Cursor 使用小例 (SQLServer)
    winform屏蔽Alt+F4组合键以防止用户关闭对话框
    SQL Server 2005 数据类型和.Net数据类型的对应关系
    php $GLOBALS 超全局变量的理解
    我改行了
    PHP $_FILES详解
  • 原文地址:https://www.cnblogs.com/wwwwyc/p/6375466.html
Copyright © 2011-2022 走看看