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=?

Hibernate Lazy属性与懒加载 整理的更多相关文章

  1. Hibernate一级缓存之懒加载问题

    Hibernate的懒加载: 当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性. 目的,为提高程序执行效率. 查询操作:get()方法/load()方法 (1)get()方法,及时 ...

  2. 计算型属性 vs 懒加载

    只实现 getter 方法的属性被称为计算型属性,等同于 OC 中的 ReadOnly 属性 计算型属性本身不占用内存空间 不可以给计算型属性设置数值 计算型属性可以使用以下代码简写 var titl ...

  3. Swift 懒加载(lazy) 和 Objective-C 懒加载的区别

    在程序设计中,我们经常会使用 懒加载 ,顾名思义,就是用到的时候再开辟空间,比如iOS开发中的最常用控件UITableView,实现数据源方法的时候,通常我们都会这样写 Objective-C - ( ...

  4. Spring - bean的lazy-init属性(懒加载)

    默认情况下,容器初始化的时候便会把bean实例化,通常这样做可以让一些配置或者bean实例化的异常在容器启动的时候就发现,而不是在N久之后.但有时候,我们希望某个可能不会用到但又不是100%不用的be ...

  5. Hibernate 性能优化之懒加载

    针对数据库中的大数据,不希望特别早的加载到内存中,当用到它的时候才加载 懒加载分为:类的懒加载.集合的懒加载.单端关联的懒加载 类的懒加载    1.在默认情况下,类就是执行懒加载        2. ...

  6. swift的计算属性和懒加载

    计算属性每次都重新计算. 懒加载只计算一次. 可以借助backing store将计算属性转化为懒加载属性. 计算属性实质上退化为函数调用. 计算属性的标示是get.set.

  7. 【Spring注解驱动开发】使用@Lazy注解实现懒加载

    写在前面 Spring在启动时,默认会将单实例bean进行实例化,并加载到Spring容器中.也就是说,单实例bean默认在Spring容器启动的时候创建对象,并将对象加载到Spring容器中.如果我 ...

  8. img 的data-src 属性及懒加载

    一.什么是图片懒加载 当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),当图片出现在浏览器的可视区域内时,才设置图片真正的路径, ...

  9. jQuery Lazy Load图片懒加载

    传送门:官网地址,jQuery Lazy Load v1.7.2下载,Github 使用方法: 1.引用js文件 <script src="jquery.js">< ...

随机推荐

  1. codeforces 691C C. Exponential notation(科学计数法)

    题目链接: C. Exponential notation time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  2. CALayer和UIView

    前言 本次分享将从以下方面进行展开: 曾被面试官问倒过的问题:层与视图的关系 CALayer类介绍及层与视图的关系 CAShapeLayer类介绍 UIBezierPath贝塞尔曲线讲解 CoreAn ...

  3. [Selenium] The commonly used validation method

    Assert.assertTrue(tmpEl.getAttribute("class").contains("selected"),"The fol ...

  4. 「LuoguP2170」 选学霸(01背包

    Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议, ...

  5. ES6之Object

    对象属性模型的相关方法: 对象自身所有属性名称 Object.getOwnPropertyNames(obj)              //[] 获取某个属性的attribute对象 Object. ...

  6. DB Link 去除域名

    1.查看global_name的设置 SQL> show parameters global_name; NAME                                 TYPE    ...

  7. 洛谷 - P2055 - 假期的宿舍 - 最大流

    https://www.luogu.org/problemnew/show/P2055 这是一个错误的示范. 一开始觉得就找一条路从外校同学连到本校同学然后最终从周末回家的同学流出,每个人睡后一个人的 ...

  8. “玲珑杯”线上赛 Round #17 河南专场 B:震惊,99%+的中国人都会算错的问题(容斥计算)

    传送门 题意 略 分析 是一道稍微变形的容斥题目,容斥一般的公式 \[ans=\sum_iAi-\sum_{i<j}{Ai∩Aj}+\sum_{i<j<k}{Ai∩Aj∩Ak}+.. ...

  9. 51nod 1062【水题】

    直接打表构造啊 #include <stdio.h> #include <string.h> #include <iostream> using namespace ...

  10. hdu 2189 悼念512汶川大地震遇难同胞——来生一起走 基础母函数

    #include <iostream> #include <algorithm> #include <cstring> using namespace std; ] ...