9.Hibernate的检索策略

1.区分立即检索和延迟检索

@Test
	public  void testLazyTrueOrFalse(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Customer c=(Customer)session.load(Customer.class, 1); //lazy=false:这个位置产生select语句
		   System.out.println("xxxxxxxxxxxxxxxxx");
		   c.getAge();   //lazy=true 这个位置产生select语句
		   tx.commit();
		   session.close();
	}
*   <class name="cn.itcast.search.Customer" table="customers" lazy="true"> 

                        class元素的lazy=true:为延迟检索,默认值

                        class元素的lazy=false:为立即检索

*   get方法永远是立即检索
2.理解延迟检索中的代理

@Test
	public  void testLazyTrueProxy(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Customer c=(Customer)session.load(Customer.class, 1);//不产生select语句
		   System.out.println(c.getClass());   //不产生select语句
		   System.out.println(c.getId());     //不产生select语句
		   System.out.println(c.getName());   //产生select语句
		   tx.commit();
		   session.close();
	}
*   只有延迟检索才会产生代理对象

*   hibernate会为产生的代理对象分配一个OID,但其他的属性不分配值,此时还没有查询

*   hibernate使用javassist-3.9.0.GA.jar包创建代理

3.初始化延迟检索中的代理

@Test
	public  void initProxy(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Customer c=(Customer)session.load(Customer.class, 1);//不产生select语句
		   System.out.println(c.getClass());   //不产生select语句
		   System.out.println(c.getId());     //不产生select语句
		   System.out.println(Hibernate.isInitialized(c));
		   //如果代理对象没有被初始化
		   if(!Hibernate.isInitialized(c)){
			   //初始化代理对象  产生select语句
			   Hibernate.initialize(c);
	       }
		   tx.commit();
		   session.close();
	}
*   Hibernate.isInitialized(c)   判断代理对象是否被初始化 对集合对象也适用

*   Hibernate.initialize(c);      初始化代理对象  hibernate执行select查询

4.区分类级别和关联级别的检索

*     类级别的检索:
      Customer c=(Customer)session.load(Customer.class, 1);
      session的方法直接检索Customer对象,对Customer对象到底采用立即检索还是延迟检索方式
      通过class元素的lazy属性设定

*    关联级别的检索:
     Customer c=(Customer)session.load(Customer.class, 1);
     Set set=c.getOrders()//检索Order对象的set集合
     在这个例子中
     session.load(Customer.class, 1):查询的主体表
     c.getOrders():查询客体表
     查询客体表是否发生,以何种方式发生(立即检索、延迟检索和迫切左外连接检索),就是关联级别检索
     通过set元素lazy属性设定

@Test
	public  void testLazyTrueProxy2(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Query query=session.createQuery("from Customer");
		   List<Customer> list=query.list();  //select
		   for(Customer c:list){
			   System.out.println(c.getId()+"   "+c.getName());
		   }
		   tx.commit();
		   session.close();
	}
*   不管lazy的值为true还是false,query.list()方法总是立即检索
5.类级别检索策略

*   如果程序加载一个对象的目的是为了访问它的属性, 可以采取立即检索. 如果程序加载一个持久化对象的目的是仅仅为了获得它的引用, 可以采用延迟检索
*   无论 <class> 元素的 lazy 属性是 true 还是 false, Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略

*   若 <class> 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句, 仅返回代理类对象的实例, 该代理类实例有如下特征:
           由 Hibernate 在运行时采用 javassist 工具动态生成
          Hibernate 创建代理类实例时, 仅初始化其 OID 属性
          在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例

6.关联级别的检索策略

*   在映射文件中, 用 <set> 元素来配置一对多关联及多对多关联关系. <set> 元素有 lazy 和 fetch 属性

@Test
	public  void testSetFetchLazy(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Customer c=(Customer)session.get(Customer.class, 1);
		   Set<Order> orderes=c.getOrderes();
		   orderes.size();
		   Iterator<Order> it=orderes.iterator();
		   while(it.hasNext()){
			   Order o=it.next();
			   System.out.println(o.getId()+"  "+o.getOrderNumber());
		   }
		   tx.commit();
		   session.close();
	}
*    <set name="orderes" table="orders"  inverse="true" fetch="join" lazy="false">

          fetch="join"  lazy="false"  采用迫切左外连接查询                一条sql语句

          fetch="join"  lazy="true"  采用迫切左外连接查询                  一条sql语句

          fetch="join"  lazy="extra"  采用迫切左外连接查询                 一条sql语句

          fetch="select"  lazy="false"  采用立即检索                            两条sql语句  先查询客户,再通过客户id查询订单

          fetch="select"  lazy="true"  采用延迟检索                              两条sql语句  先查询客户,再通过客户id查询订单

         fetch="select"  lazy="extra"  采用延迟检索  极其懒惰  上面的例子中只会查询orders集合的大小           两条sql语句  先查询客户,再通过客户id查询订单

         fetch="subselect"  lazy="false"  采用立即检索                      两条sql语句  先查询客户,再通过客户id查询订单

          fetch="subselect"  lazy="true"  采用延迟检索                       两条sql语句  先查询客户,再通过客户id查询订单

         fetch="subselect"  lazy="extra"  采用延迟检索  极其懒惰  上面的例子中只会查询orders集合的大小             两条sql语句  先查询客户,再通过客户id查询订单

*      上面subselect不会出现子查询,因为客户只查询了一个,而子查询中的in语句是存放多个的,这里没有子查询的语句出现
@Test
	public  void QuerySetFetchLazy(){
		   Session session=sf.openSession();
		   Transaction tx=session.beginTransaction();
		   Query query=session.createQuery("from Customer c");
		   List<Customer> list=query.list();
		   list.get(0).getOrderes().size();
		   tx.commit();
		   session.close();
	}

<set name="orderes" table="orders"  inverse="true" fetch="join" lazy="false">

          fetch="join"  lazy="false" 立即检索客户关联到订单集合     4条sql语句  一条查询客户  3条查询客户对应的订单

          fetch="join"  lazy="true"  延迟检索客户关联到订单集合      4条sql语句   一条查询客户  3条查询客户对应的订单

          fetch="join"  lazy="extra"  增强延迟检索客户关联到订单集合(要什么查什么)   4条sql语句      一条查询客户  3条查询客户对应的订单集合的大小

          fetch="select"  lazy="false"  立即检索客户关联到订单集合     4条sql语句  一条查询客户  3条查询客户对应的订单

          fetch="select"  lazy="true"  延迟检索客户关联到订单集合      4条sql语句   一条查询客户  3条查询客户对应的订单

         fetch="select"  lazy="extra"  增强延迟检索客户关联到订单集合(要什么查什么)   4条sql语句      一条查询客户  3条查询客户对应的订单集合的大小

         fetch="subselect"  lazy="false"  采用立即检索                      两条sql语句  先查询客户,再通过子查询查询订单

          fetch="subselect"  lazy="true"  采用延迟检索                       两条sql语句  先查询客户,再通过子查询查询订单

         fetch="subselect"  lazy="extra"  采用延迟检索  极其懒惰  两条sql语句  先查询客户,再通过子查询查询订单集合的大小

*    因为查出来是Customer对象集合,所以不会迫切左外连接查询 如果语句改为这样 Query query=session.createQuery("from Customer c where c.id=1");  就是迫切左外连接查询

*   在延迟检索(lazy 属性值为 true) 集合属性时, Hibernate 在以下情况下初始化集合代理类实例 
    应用程序第一次访问集合属性: iterator(), size(), isEmpty(), contains() 等方法
    通过 Hibernate.initialize() 静态方法显式初始化
*  增强延迟检索(lazy 属性为 extra): 与 lazy=“true” 类似. 主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机:
         当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders 集合代理类实例的初始化
         当程序第一次访问 order 属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化 orders 集合类的实例, 仅通过特定的 select 语句查询必要的信息, 不会检索所          有的 Order 对象

7.多对一和一对一关联的检索策略

*   <many-to-one fetch="join" lazy="false">

              fetch="join" 

                      * 如果使用get方式检索,   lazy="false/proxy/no-proxy"总是使用迫切左外连接检索

                      *如果使用query方式检索,

                                     lazy="false ,这时不再采用切左外连接检索,而是采用立即检索  先查询订单,再通过订单的表的外键id查询客户  4条语句  先查订单 再查订单对应的客户
                             lazy="proxy,这时不再采用切左外连接检索,而是采用延迟检索  先查询订单,再通过订单的表的外键id查询客户  4条语句  先查订单 再查订单对应的客户   

                                     lazy="no-proxy",这时不再采用切左外连接检索,而是采用延迟检索  先查询订单,再通过订单的表的外键id查询客户  4条语句  先查订单 再查订单对应的客户                  fetch=select
                      *lazy="false" 立即检索(先查询订单,在通过订单的外键查询客户)

                     *lazy="proxy"

                              * 对端的class元素中的lazy="false",立即检索
                     <class name="cn.itcast.search.Customer" table="customers" lazy="false">
                     * 对端的class元素中的lazy="true",延迟检索
                     <class name="cn.itcast.search.Customer" table="customers" lazy="true">

8.1组合1  many2one立即检索+set立即检索

输出如下语句

*select * from orders where id=?

*Select* from customers where id=?

*Select *  from orders where customer_id=?

8.2组合2  many2one迫切左外+set立即检索

输出如下语句

*select * from orders o left outer join customers  c  on c.id=o.customer_idwhere o.id=?

*Select *  from orders where customer_id=?

8.3组合3  many2one立即检索+set迫切左外

输出如下语句

*Select * from order where id=?

*select * from orders o left outer join customers  c  on c.id=o.customer_idwhere c.id=?

9.1 批量检索  从一的一端查询  查询所有的客户

*   <set> 元素有一个 batch-size 属性, 用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能.  默认值是

 <set name="orderes" table="orders"  inverse="true" fetch="select" lazy="true" batch-size="2">
9.2 批量检索  从多的一端查询  查询所有的订单

<class name="cn.itcast.search.Customer" table="customers" lazy="true" batch-size="2">

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值