lazy概念:要用到的时候,再去加载,对于关联的集合来说,只有当访问到的时候,才去加载它所关联的集合,比如一个user对应很多权限,只有当user.getRights()的时候,才发出select right的语句,在访问到rights之前,rights是一个PersisitSet对于实体类来说,只有当它的属性被访问到时,才会真正加载这个实体类,在它的属性没有被访问到之前,这个实体类是一个代理对象。

1.在集合中定义:<set><list>标签上

,可以取值:true/false/extra

<set name="name" lazy="true/false/extra" >
默认为true

默认为true情况下,当使用到了Set对象,才会把整个set全部查询出来。

false情况下,不使用Lazy,查询Lazy所属的对象时,set就会被查询上来。extra情况下,比较智能,根据查询的内容,生成不同的SQL语句。效率会高一些。

例子:在我们前边多对一的关系中(部门与员工):

Department.hbm.xml:

[html] view plain copy

print?

  1. <set name="emps" inverse="true" lazy="false">  
  2.             <key column="depart_id" />  
  3.             <one-to-many class="Employee" />  
  4.         </set>  

通过这个可以关闭默认的懒加载

单端关联 <one-to-one><many-to-one>单端关联上,可以取值:false/proxy/no-proxy

<many-to-one name="name" lazy="false/proxy/no-proxy">
默认为proxy

false:不使用Lazy。此关联总是被预先抓取

proxy:使用懒加载

no-proxy:指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)

[html] view plain copy

print?

  1. <many-to-one name="depart" column="depart_id" lazy="false"/>   
  • lazy="proxy" applies to single objects (ie foo.SingleBar)
  • lazy="true" applies to collections of objects (ie foo.MultiBar)

(You can't set lazy="proxy" to a collection, nor can you set lazy="true" to a single reference. Either will cause NH to throw a XmlSchemaException which is a little cryptic to beginners.)

比如说在college.hbm.xml里面写上

<set name="majors" inverse="true" lazy="false" cascade="delete">

加载学院时立刻加载学院的专业,那么在查询所有学院时,产生的sql语句如下:

Hibernate: select majors0_.college_id as college_2_3_0_, majors0_.major_id as major_id1_6_0_, majors0_.major_id as major_id1_6_1_, majors0_.college_id as college_2_6_1_, majors0_.major_name as major_na3_6_1_, majors0_.major_code as major_co4_6_1_ from studorm.tb_major majors0_ where majors0_.college_id=?

在查询所有学院的时候,会立刻加载每个学院的专业,所以如非必要,不要加上

十分浪费资源

以下来自:http://www.cnblogs.com/wukenaihe/archive/2013/06/11/3131640.html

3.class标签

除了用在<set> 和  <one-to-one><many-to-one>标签上,lazy还能用在

* <class>标签上,可以取值:true/false ,在hibernate3以上版本,默认是true
* <property>标签上,可以取值:true/false

在<class>标签上,可以取值:true/false ,在hibernate3以上版本,默认是true

默认为true,可不写,在执行查询语句时不进行,比如session.load(id)时,不执行sql语句(session.get(id)不支持lazy),而是在具体获取参数时,执行sql语句,比如obj.getName()。

<class>标签上的lazy特性只对普通属性起作用

<class>标签上的lazy不会影响到单端关联上的lazy特性

3.1 延迟加载策略(默认)

  如果想对实体对象使用延迟加载,必须要在实体的映射配置文件中进行相应的配置

  <class name="Person" table="PERSON" lazy="true">

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("0: "+p.getPersonId());//(2)

4 System.out.println("0: "+p.getName());//(3)

5 tx.commit();

6 session.close();

  执行到(1)并没有出现sql语句,并没有从数据库中抓取数据。这个时候查看内存对象p如下:

图2.1 person对象load时的内存快照

  观察person对象,我们可发现是Person$$EnhancerBy..的类型的对象。这里所返回的对象类型就是Person对象的代理对象,在hibernate中通过使用CGLB来先动态构造一个目标对象的代理类对象,并且在代理对象中包含目标对象的所有属性和方法。所以,对于客户端而言是否为代理类是无关紧要的,对他来说是透明的。这个对象中,仅仅设置了id属性(即personId的值),这是为了便于后面根据这个Id从数据库中来获取数据。

,但是仍然没有从数据库里面读取数据。这个时候代理类的作用就体现出来了,客户端觉得person类已经实现了(事实上并未创建)。但是,如果这个会后session关闭,再使用person对象就会出错了。

调试运行到(3)处,要用到name属性,但是这个值在数据库中。所以hibernate从数据库里面抓取了数据,sql语句如下所示:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  这时候,我们查看内存里面的对象如下:

图2.2 class延迟加载时内存对象

  真正的Person对象放在CGLIB$CALLBACK_0对象中的target属性里。

  这样,通过一个中间代理对象,Hibernate实现了实体的延迟加载,只有当用户真正发起获得实体对象属性的动作时,才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的,所以只有session.load()方法才会利用实体延迟加载,因为只有session.load()方法才会返回实体类的代理类对象。

3.2 非延迟加载策略

  Hibernate默认的策略便是非延迟加载的,所以设置lazy=false

  

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("0: "+p.getPersonId());//(2)

4 System.out.println("0: "+p.getName());//(3)

5 tx.commit();

6 session.close();

  调试运行到(1)处时,hibernate直接执行如下sql语句:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  我们在查看内存快照如下:

这个时候就不是一个代理类了,而是Person对象本身了。里面的属性也已经全部普通属性也全部被加载。这里说普通属性是因为addresses这个集合对象并没有被加载,因为set自己本身也可以设置lazy属性。所以,这里也反映出class对象的lazy并不能控制关联或集合的加载策略。

2.3 总结

  Hibernate中<class lazy="">默认为true。如果,在load的时候只会返回一个代理类,并不会正在从数据库中读取数据。第一次用到时,会将所有普通属性(set这种就不是)全部加载进来。如果第一次使用到时,session已经关闭将发生错误。

  如果显式是设置lazy=false,load的时候即会把所有普通属性全部读取进来。而且,返回的将是一个真正的该类型的对象(如Person),而不是代理类。

4字段加载(property)

  在Hibernate3中,引入了一种新的特性——属性的延迟加载,这个机制又为获取高性能查询提供了有力的工具。在大数据对象读取时,如Person对象中有一个School字段,该字段是一个java.sql.Clob类型,包含了用户的简历信息,当我们加载该对象时,我们不得不每一次都要加载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会带来很大的性能开销。

 <class lazy="false">

  配置如下

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("");//(2)

4 System.out.println("0: "+p.getPersonId());//(3)

5 System.out.println("0: "+p.getName());//(4)

6 System.out.println("0: "+p.getSchool());//(5)

7 tx.commit();

1
<property name="name" type="java.lang.String">

2
<column name="NAME"
/>

3
</property>

4
<property name="school" type="java.lang.String" lazy="true">

5
<column name="SCHOOL"></column>

6
</property>

的时候,全部加载了,执行语句如下:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_,

person0_.SCHOOL as SCHOOL3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  所有普通属性都均已加载。

<class lazy="true">

)时,也同样加载了全部属性,执行了如下sql:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_,

person0_.SCHOOL as SCHOOL3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  结果就是无效,不管采用何种策略都是无效的,和我们想想的有较大出路。下面是一段来自hibernate官方文档的话。

  Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.

  应该是因为,我们并未用到编译时字节码增强技术的原因。如果只对部分property进行延迟加载的话,hibernate还提供了另外的方式,也是更为推荐的方式,即HQL或者条件查询。

  A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.

实例

User和rights是双向一对多,一个user有多条权限,在user.hbm.xml里这么配置

<!-- 权限和用户的关系由权限来掌控,采用懒加载 -->

<set name="rights" inverse="true"   cascade="delete" >

<key>

<column name="user_rowcount" not-null="true" />

</key>

<one-to-many class="com.studorm.entity.Right" />

</set>

当通过user获取他的所有权限的时候,可以这么写:

Session session=getCurrentSession();

User user=(User)session.get(User.class, userRowcount);

Set<Right> rights=(Set<Right>)user.getRights();

//注意user.getRights()返回PersisitSet是set的子类,不是HashSet的子类.HashSet<Right> rights=(HashSet<Right>)user.getRights()抛异常

System.out.print("获取用户 "+user.getLoginId()+"的权限有"+rights.size()+"条: ");

Iterator<Right> iter = rights.iterator();

while (iter.hasNext())

{

Right right= it.next();

}

产生的sql语句:

Hibernate: select user0_.user_rowcount as user_row1_9_0_, user0_.manage_college_id as manage_c2_9_0_, user0_.login_id as login_id3_9_0_, user0_.login_pwd as login_pw4_9_0_, user0_.user_type as user_typ5_9_0_, user0_.user_phone as user_pho6_9_0_ from studorm.tb_user user0_ where user0_.user_rowcount=?

Hibernate: select rights0_.user_rowcount as user_row2_9_0_, rights0_.right_rowcount as right_ro1_7_0_, rights0_.right_rowcount as right_ro1_7_1_, rights0_.user_rowcount as user_row2_7_1_, rights0_.function_id as function3_7_1_ from studorm.tb_right rights0_ where rights0_.user_rowcount=?

最新文章

  1. html中select标签根据枚举获得值的总结
  2. flv转mp4选项设置
  3. python 树遍历
  4. Docker-2:network containers
  5. 采用xml的方式保存数据
  6. Chrome浏览器 54 版本显示“Adobe flash player已过期”问题解决
  7. j2ee中的2是什么意思
  8. GCD之全局、主线程
  9. levmar ndk 编译
  10. 微服务框架——SpringCloud
  11. Oracle Profile 配置文件
  12. 快速入门Treap(代码实现)
  13. 自定义gradle插件
  14. ios12 siri 语音识别
  15. Mysql数据库优化之SQL及索引优化
  16. MySQL 出现You can&#39;t specify target table for update in FROM clause错误解决方法
  17. logback debug 日志没有信息
  18. JSP内置对象之WEB安全性及config对象
  19. Centos 配置ifconfig命令
  20. Python学习-33.Python中glob模块的一些参数

热门文章

  1. Java 给Thread传递参数
  2. Ubuntu 12.04 nethogs 流量监控查看
  3. CodeForces-884D:Boxes And Balls(合并石子)
  4. jsch上传文件功能
  5. 洛谷P1247取火柴游戏
  6. ASP.NET Core:Pages
  7. bzoj4555
  8. LeNet-5结构分析及caffe实现————卷积部分
  9. windows下安装RabbitMQ消息服务器 + 读写队列
  10. sql server2008配置管理工具服务显示远程过程调用失败