城东小巷分享 http://blog.sciencenet.cn/u/chengdong166

博文

Hibernate检索策略

已有 3371 次阅读 2013-9-12 22:33 |个人分类:Java学习|系统分类:科研笔记| Hibernate, 检索策略

一、Hibernate检索策略
1.  立即检索策略:检索一个对象时会把与之关联的对象检索出来。这种检索策略的不足之处在于:(1)需要频繁地访问数据库,影响检索性能;(2)往往多加载一些多余的对象,这会造成内存空间资源的浪费。
2.  延迟检索策略:避免加载多余的对象,防止空间资源浪费。
3.  迫切左外连接策略:利用SQL的外连接的查询功能,减少检索SQL语句的条数。

二、检索策略类型
1.  类级别:是否采用延迟检索或立即检索策略检索指定的类对象,如Session的load()和get()方法、Query的HQL语句检索类对象。
2.  关联级:是否采用延迟检索、立即检索或迫切左外连接检索策略检索对象及与之关联的其他对象。此外,延迟检索和立即检索策略都可以设置批量检索数量。

   说明:类级别的延迟检索仅影响Session的load()方法,比如:

      类级别采用延迟加载策略,当执行Session的load()方法时,Hibernate不会执行select语句,而是返回一个Customers 类的代理类(Hibernate采用CGLIB工具来生成持久化类的代理类)的实例,这个代理类具有以下特征:

(1) 由Hibernate运行时动态生成,它扩展了Customers 类,因此具有Customers 类的所有属性和方法。

(2) 当创建Hibernate代理类实例时,仅初始化了它的OID属性,其余属性都为null。

(3) 当应用程序第一次调用Customers代理类实例时,Hibernate会初始化代理类实例,在初始化过程中执行select语句,真正从数据库中加载Customers对象的所有数据,例如:

      Customers c2 = (Customers)session.load(Customers.class, new Long(5));
      c2.getName();//这是执行select语句
控制台打印出SQL语句为
Hibernate: select customers0_.ID as ID4_0_, customers0_.name as name4_0_ from customers customers0_ where customers0_.ID=?

      当然也有例外,当应用程序访问代理类的实例的getId时,由于在创建代理类实例时OID已存在,因此Hibernate不会到数据库中查询。

        // 不会执行select语句,返回id为5其它属性为null的代理类对象,

       Customers c2 = (Customers)session.load(Customers.class, new Long(5));
       c2.getId();//也不执行sql语句
控制台未打印出SQL语句。

       通过以上分析,如果仅仅是为了获取对持久化对象的引用,可以采用延迟加载;如果是为了访问持久化类对象的属性,可以采用立即检索。
三、映射文件中用于设定检索策略的几个属性
1.  <class>元素中的lazy:true(延迟检索,默认)、false(立即检索)。
2.  <set>元素中的属性:(1)lazy:true(延迟检索,默认)、false(立即检索)和extra(增强延迟检索);(2)fetch:select(select查询语句,默认)、subselect(带子查询的select语句)和join(迫切左外连接检索)。
3.  <many-to-one>元素中的属性:(1)lazy:proxy(延迟检索)、no-proxy(无代理延迟检索)和false(立即检索);(2)fetch:select(select查询语句,默认)和join(迫切左外连接检索)。
4.  设置批量检索数量属性batch-size:可选值为正整数,默认值为1。仅适用于关联级的延迟检索和立即检索,合理值为3-10。在<class>和<set>元素中设置此属性。
       由于映射文件配置的检索策略固定的,无法满足各种应用逻辑的动态化需求,因此Hibernate提供了以编程方式显示设定检索策略。

四、Session的get方法与load方法在检索策略的区别
1.  采用类级别延迟加载,会影响Session的load()方法的各种运行时行为
   (1)装载一个在数据库中不存在的Customers对象时,若从未访问该对象的方法(除id的setter和getter方法外),则执行load()方法不会抛出异常,直到访问该对象的方法时候才会抛出:

                     org.hibernate.ObjectNotFoundException
   (2)若处于Session实例的生命周期内通过load()方法返回的Customers代理类对象一直未被初始化(未执行select语句),则当该对象处于游离状态时,访问该对象的属性方法(除访问代理类实例的getId()方法外)时就会抛出异常:
                  org.hibernate.LazyInitializationException: could not initialize proxy - no Session
   
(3)org.hibernate.Hibernate.initialize(Object)用于显示初始化Session范围内的代理类实例。
                     Session hibernateSession = InitSessionUtil.openSession();
                     Customers customer = (Customers)hibernateSession.load(cls, id);
                     // 判断代理类实例是否已被初始化,若否则初始化代理类实例
                     if (!Hibernate.isInitialized(customer)) {
                          Hibernate.initialize(customer);
                     }
                     InitSessionUtil.closeSession();
           这样,当customer对象处于游离状态时,仍然可以访问该对象了。
   (4)访问代理类实例的getId()方法时,由于代理类的OID值已存在,无需访问数据库,因此不会初始化代理类实例。
2. 不管<class>元素的属性lazy设置为true或者是false,Session的get()方法及Query的list()方法在Customers类级别总是采用立即检索策略。如果在数据库中不存在该记录,则返回null。get()方法永远不会返回代理类实例。

 

 


 

 



https://blog.sciencenet.cn/blog-448935-724430.html

上一篇:映射一对多关联关系
下一篇:Hibernate检索策略(二)
收藏 IP: 122.82.216.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-5-19 01:04

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部