Hibernate性能优化 --- 延迟加载(懒加载)

 

 

一 延迟加载概述

Hibernate中主要是通过代理机制来实现延迟加载的。

目的:为了减少和数据库交互的次数,推迟和数据库交互的时间

过程:Hibernate从数据库获取某一个对象时,获取某一个对象的集合属性值时,或获取某一个对象所关联的另一个对象时,由于没有使用该对象的数据,Hibernate并不从数据库加载真正的数据,而只是为该对象创建一个代理对象来代表这个对象,这个对象上的所有属性都为默认值,只有在真正需要使用该对象的数据时才创建这个真正的对象,真正从数据库中加载它的数据,在某种情况下,可以提高查询效率。

二 实例使用:

1.session.load()

public static User getUser(int id) {

Session session = null;

try {

session = HibernateUtil.getSession();

Class clazz = User.class;

User user = (User) session.load(clazz, id);

//强迫用户初始化,在什么时候使用的时候即可调用数据库

Hibernate.initialize(user);

return user;

} finally {

// 使资源得到释放

if (session != null) {

session.close();

}

}

}

说明:

1)懒加载load()在运行后没有立刻访问相应的数据库,返回的是代理对象,通过new关键字创建一个代理对象 User_$$_javassist_7类,它是User的一个子类,是User动态创建的,所以强制造型没有错,是为了使代理对象不冲突。

2)懒加载是通过代理对象实现的,代理对象比domain功能要强大,是domain类对象的子类,代理对象返回的是从数据库中查找到的,而不是代理对象的查找的是domain中的属性。

3)代理对象永远不可能为空,所以判空无意义。

4)代理对象的使用是有限制的:必须是在和代理对象关联的session关闭之前使用

5)当确实需要这个用户的数据时,才会访问数据库

6Hibernate.initialize()是初始化是强迫使用User对象

7)当在懒加载之后,调用getID()不会有输出,没有查询数据库的操作,因为id值已经传过来了。getClass()getId()一样,不用操作数据库就可以得到

2.集合的关联的懒加载

1)一对一的关联

当在查主对象person的时候,将PersonIdCard左外连接查询出来person对象和idCard对象,没有懒加载,原因是对性能没有什么提高

当在查从对象idCard的时候,对于idCard所关联的person对象是懒加载的。当在主方法中调用的时候,会抛异常,可以在得到从对象之后,初始化从对象的主对象就可以,用的语句是:

Hibernate.initialize(idCard.getPerson());也可以在idCard的映射文件中取消懒加载,即lazy=false;

一对一的关联满足懒加载的条件:

1)主表不能有constrained=true,所以主表没有懒加载

2)从表中lazy!=false

3fetch=select 是缺省的值

2)一对多的关联

Department department = (Department) session.get(Department.class,depId);

上面一句话当现实执行的sql语句时,输出的语句是一条查询depart的语句,而没有输出Employee的查询语句,是因为employee的信息放到了代理对象的集合属性中,如果把懒加载的功能取消了,在查询的时候会把员工的信息也查询出来,而在不需要员工的时候也会查询出来,这样不会提高Hibernate的工作效率。

注:

//输出的是代理对象

System.out.println(department.getEmps().getClass());

3)多对一的关联

在一的一方,相当于获取到Employee,查询的只是employee的信息,而部门的信息是放到代理对象中的,但是员工只能属于一个部门,所以用不用懒加载是没什么关系的,相当于是一对一中的影响不是很大。

4lazyfetch介绍

lazy是指相关联的属性什么时候抓取

fetch通过什么方式来进行抓取,fecth=join时,会把两条select连接成一条语句,lzay属性不起作用

如果抓取策略改为join的话,懒加载就会取消。

Hibernate懒加载深入分析

----------------------------------------------------------
懒加载可以提高性能吗? 
不可以简单的说"",因为Hibernate的关系映射拖累了SQL的性能,所以想出懒加载来弥补.只是弥补而以,不会超越.所以大家不要想着使用了懒加载总体性能就提高了,其实总体性能不下降就万幸了.
----------------------------------------------------------
Hibernatelazy属性可以配置在: 

(常用)<set><list>标签上 ,可以取值true,false,extra
            默认为true,当为true,会懒加载,访问集合属性时再发出SQL语句.set.size(),很不智能,不会生成count()语句,而是查出所有记录赋值给set.
            extra说明:调用集合的set.size(),会生成select count(*)from tableName,比较智能.建议使用
(少用)<many-to-one><one-to-one>标签上 ,可以取值false,proxy,noproxy
            当为true,会有懒加载特性,当为false时会产生N+1问题,比如一个学生对应一个班级,用一条SQL查出10个学生,当访问学生的班级属性时Hibernate会再产生10SQL分别查出每个学生对应的班级.
(不用)<class>标签上 ,可以取值true,false
            默认为true,当为false,load()方法将失去懒加载的特性与get()一样,不影响集合(<set><list>)标签上的lazy特性
(不用)<property>标签上 ,可以取值true,false 
            默认值为false,懒加载某个字段,无意义,不要使用

----------------------------------------------------------
get()load()的区别 
get()无懒加载特性,马上执行SQL查询.
load()有懒加载特性,会返加一个代理对象,所以永远不为null,先不执行SQL,要取对象的值时才执行SQL语句,前题session不能关闭,<class>标签上lazy不为false.

----------------------------------------------------------
实现懒加载的前提: 1 PO不能是final
能实现懒加载的对象(PO)都是被CGLIB改写的代理对象,所以不能是final修饰的
须要asm,cglib两个jar
相应的lazy属性为true
相应的fetch属性为select 
----------------------------------------------------------
什么时候出遇到懒加载 
使用load()
一对一<one-to-one> 
查主对象 默认使用join连接,不会发生懒加载
查从对象 默认会发生懒加载,先执行一句select查出从对象,当通过从对象访问了主对象时,再执行一句select查出主对象.

多对一<many-to-one>
在使用hbm.xnl时,取多的一方时,默认会懒加载,不取一的一方
在使用JPA时,取多的一方时,默认自动使用join on语句取出一的一方(用户与组,用户是多的一方,组是一的一方)

一对多(<set><list>)
默认会懒加载,这是必须的,是重常用的。

----------------------------------------------------------
实现懒加载的方案:
方法一:(没有使用懒加载)   
用 Hibernate.initialize(de.getEmps()) 提前加载一下. 

方法二:
把与Session脱离的对象重新绑定
lock()方法是用来让应用程序把一个未修改的对象重新关联到新session的方法。

//直接重新关联


session.lock(fritz, LockMode.NONE);


//进行版本检查后关联


session.lock(izi, LockMode.READ);


//使用SELECT ... FOR UPDATE进行版本检查后关联


session.lock(pk, LockMode.UPGRADE);

fetch 和 lazy 配置用于数据的查询 

lazy 参数值常见有 false 和 trueHibernate3 映射文件中默认lazy = true  

fetch 指定了关联对象抓取的方式,参数值常见是selectjoin,默认是select, select方式先查询主对象,再根据关联外键,每一个对象发一个select查询,获取关联的对象,形成了n+1次查询;而join方式,是left outer join查询,主对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。 

在映射文件中,不同的组合会使用不同的查询: 
1lazy="true" fetch = "select" ,使用延迟策略,开始只查询出主对象,关联对象不会查询,只有当用到的时候才会发出sql语句去查询 ; 

2lazy="false" fetch = "select" ,没有用延迟策略,同时查询出主对象和关联对象,产生1+nsql. 

3lazy="true"lazy="false" fetch = "join",延迟都不会作用,因为采用的是外连接查询,同时把主对象和关联对象都查询出来了. 

另 外,在hql查询中,配置文件中设置的join方式是不起作用的,而在其他查询方式如getcriteria等是有效的,使用 select方式;除非在hql中指定join fetch某个关联对象。fetch策略用于get/load一个对象时,如何获取非lazy的对象/集合。 这些参数在Query中无效。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值