hibernate延迟加载分析
来源:互联网 发布:网络代刷平台 编辑:程序博客网 时间:2024/05/22 23:26
在hibernate中我们知道如果要从数据库中得到一个对象,通常有两种方式,一种是通过session.get()方法,另一种就是通过session.load()方法,然后其实这两种方法在获得一个实体对象时是有区别的,在查询性能上两者是不同的。
一.load加载方式
当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象,即:当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询我们的对象。
session = HibernateUtil.getSession();Type type = (Type) session.load(Type.class, 9);
通过load的方式加载对象时,会使用延迟加载机制,此时并不会发出sql语句,只有当我们需要使用的时候才会从数据库中去查询
请看下面的一段代码:
@Testpublic void testLoad() {Session session = null;try {session = HibernateUtil.getSession();Type type = (Type) session.load(Type.class, 9); System.out.println("load加载 时 类型 "+ type.getClass());Type t = (Type) session.get(Type.class, 11);System.out.println("get加载 时 类型 "+t.getClass());System.out.println("load 加载 sql 语句的发送时间 ------");System.out.println(type.getName());} catch (Exception e) {e.printStackTrace();} finally {if (session != null) {session.close();}}}
请看执行结果:
load加载 时 类型 class com.lgh.hibernate.entity.Type_$$_jvstd0_0Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?get加载 时 类型 class com.lgh.hibernate.entity.Typeload 加载 sql 语句的发送时间 ------Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?水果通过结果我们发现 当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,实际上我们得到的是hibernate 帮我们动态生成的Type 子类 ,如果我们要使用该对象时获取除ID的其他属性时,此时我们看到控制台会发出了sql查询语句,会将该对象从数据库中查询出来
二、get加载方式
相对于load的延迟加载方式,get就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,此时都会发出sql语句去从数据库中查询出来
@Testpublic void testGet() {Session session = null;try {session = HibernateUtil.getSession();Type t = (Type) session.get(Type.class, 11);System.out.println("get加载 时 类型 "+t.getClass());} catch (Exception e) {e.printStackTrace();} finally {if (session != null) {session.close();}}}
Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?get加载 时 类型 class com.lgh.hibernate.entity.Type
get与load 的 另一些区别
get 和load 在加载方式上的不同 也使它们查询ID不存在的对象时所引发异常也不相同
如果使用get方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报NullPointException的异常
Type t = (Type) session.get(Type.class, 3434);System.out.println("get加载 时 类型 "+t.getClass());Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?java.lang.NullPointerExceptionat com.lgh.hibernate.test02.HibernateCache.testGet(HibernateCache.java:121)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ....
这是因为通过get方式我们会去数据库中查询出该对象,但是这个id值不存在,所以此时Type对象是null,所以就会报NullPointException的异常了。
如果使用load方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报ObjectNotFoundException异常:
session = HibernateUtil.getSession();Type t = (Type) session.load(Type.class, 3434);System.out.println("load加载 时 类型 "+t.getClass());System.out.println(t.getName());
load加载 时 类型 class com.lgh.hibernate.entity.Type_$$_jvstd0_0Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.lgh.hibernate.entity.Type#3434]
为什么使用load的方式和get的方式来得到一个不存在的对象报的异常不同呢??其原因还是因为load的延迟加载机制,使用load时,此时的Type对象是一个代理对象,仅仅保存了当前的这个id值,当我们试图得到该对象的name属性时,这个属性其实是不存在的,所以就会报出ObjectNotFoundException这个异常了。
我们在编写javaweb 项目 时通常 都采用分层写法 ,把像操作数据库的的一些方法封装到一个类中,统一管理 ,一般我们都把它们命名为Dao 层 ,现在我们模拟一个TypeDao
类的getType()方法
package com.lgh.hibernate.test02;import org.hibernate.Session;import com.lgh.hibernate.entity.Type;import com.lgh.hibernate.util.HibernateUtil;public class TypeDao { public static void main(String[] args) { TypeDao hc = new TypeDao(); Type t = hc.getType(); System.out.println("----"+t.getName()); } public Type getType(){ Session session = null; try { session = HibernateUtil.getSession(); Type t = (Type) session.load(Type.class, 11); return t; } catch (Exception e) { e.printStackTrace(); } finally { if (session != null) { session.close(); } } return null; }}
模拟了一个TypeDao这样的对象,然后我们在测试用例里面来通过load加载一个对象,此时我们发现控制台会报org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Sessionat org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)at com.lgh.hibernate.entity.Type_$$_jvst5e0_0.getName(Type_$$_jvst5e0_0.java)at com.lgh.hibernate.test02.TypeDao.main(TypeDao.java:13)
这个异常是什么原因呢??还是因为load的延迟加载机制,当我们通过load()方法来加载一个对象时,此时并没有发出sql语句去从数据库中查询出该对象,当前这个对象仅仅是一个只有id的代理对象,我们还并没有使用该对象,但是此时我们的session已经关闭了,所以当我们在测试用例中使用该对象时就会报LazyInitializationException这个异常了。
所以以后我们只要看到控制台报LazyInitializationException这种异常,就知道是使用了load的方式延迟加载一个对象了,解决这个的方法有三种,一种是将load改成get的方式来得到该对象,另一种是在表示层来开启我们的session和关闭session,还有一种就是。
在dao层load方法后面加上:
Hibernate.initialize(t);
public Type getType() {Session session = null;try {session = HibernateUtil.getSession();Type t = (Type) session.load(Type.class, 11);// 强制初始化 发送SQL语句向数据库拿数据Hibernate.initialize(t);return t;} catch (Exception e) {e.printStackTrace();} finally {if (session != null) {session.close();}}return null;}
Load延迟加载的管理
通过上面我们知道使用load方法会产生延迟加载现象那怎么配置让load方法跟get方法一样呢
这有多种方式:
在配置实体类的映射文件添加lazy属性
lazy 属性默认为true 当我们不配置或为true时 ,通过load方法就会有延迟加载,当lazy = “false”时 load方法就会与get方法没什么区别了
<hibernate-mapping> <class name="com.lgh.hibernate.entity.Type" table="T_TYPE" lazy="false"> ..... </class> <!-- 我们编写的HQL语句 --> <query name="getAll"> from Type where id > ? </query></hibernate-mapping>
Type t = (Type) session.load(Type.class, 11);System.out.println("load加载 时 类型 "+t.getClass());
Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?load加载 时 类型 class com.lgh.hibernate.entity.Type
我们发现 我们没有访问Type的其他属性 但是当调用load方法时 发出了查询语句 并且此时返回值的类型不再是代理子类 而是type类本身
看到了上面的代码,我们注意到 load 查找时返回返回值的类型是代理子类,其是要继承Type类的才可以产生代理子类 那么当Type类为final 时 ,不能被继承load方法是否还会延迟加载呢?
第二种方法 把实体类 final
Type t = (Type) session.load(Type.class, 11);System.out.println("load加载 时 类型 "+t.getClass());
Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?load加载 时 类型 class com.lgh.hibernate.entity.Type
我们看到把类修改成不能被继承 此时延迟加载 也不能发挥作用了
关联对象的延迟加载
一对多关联
Type 与Product 时 一对多关系
当在一对多关联映射模式下
fetch="select"
<!-- class="com.lgh.hibernate.entity.Type" fetch="join" --> <!-- fetch 控制如何查关联对象, join 采用外连接去拿关联对象 没有产生延迟加载行为 select 另外发送查询语句查询 lazy : 三种 值: - false - proxy - no-proxy --> <many-to-one name="type" cascade="save-update" fetch="select" > <column name="tid" /> </many-to-one>
当没有配置lazy 时
我们同过 get方法:
session = HibernateUtil.getSession(); Product p = (Product) session.get(Product.class, 26); System.out.println("-------------"); System.out.println(p.getType().getName());结果:
Hibernate: select product0_.ID as ID1_3_0_, product0_.NAME as NAME2_3_0_, product0_.PATH as PATH3_3_0_, product0_.DESCRI as DESCRI4_3_0_, product0_.PRICE as PRICE5_3_0_, product0_.tid as tid6_3_0_ from T_PRODUCT product0_ where product0_.ID=?-------------Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?水果
我们发现 在 需要用到type 时 才会向数据库查询 在查询关联对象时发生延迟加载
当使用 load方法时:
session = HibernateUtil.getSession(); Product p = (Product) session.load(Product.class, 26); System.out.println("---------------"); System.out.println(p.getName()); System.out.println("-------------"); System.out.println(p.getType().getName());;
---------------Hibernate: select product0_.ID as ID1_3_0_, product0_.NAME as NAME2_3_0_, product0_.PATH as PATH3_3_0_, product0_.DESCRI as DESCRI4_3_0_, product0_.PRICE as PRICE5_3_0_, product0_.tid as tid6_3_0_ from T_PRODUCT product0_ where product0_.ID=?西瓜-------------Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?水果我们发现 使用product对象其他属性时向数据库发送查询语句
在 需要用到 type 时 才会向数据库查询 在查询关联对象时发生延迟加载
当我们配置
lazy="false" fetch="select"
<!-- class="com.lgh.hibernate.entity.Type" fetch="join" --> <!-- fetch 控制如何查关联对象, join 采用外连接去拿关联对象 没有产生延迟加载行为 select 另外发送查询语句查询 lazy : 三种 值: - false - proxy - no-proxy --> <many-to-one name="type" cascade="save-update" lazy="false" fetch="select" > <column name="tid" /> </many-to-one>
load方法 :
session = HibernateUtil.getSession(); Product p = (Product) session.load(Product.class, 26); System.out.println("---------------"); System.out.println(p.getName()); System.out.println("-------------"); System.out.println(p.getType().getName());
---------------Hibernate: select product0_.ID as ID1_3_0_, product0_.NAME as NAME2_3_0_, product0_.PATH as PATH3_3_0_, product0_.DESCRI as DESCRI4_3_0_, product0_.PRICE as PRICE5_3_0_, product0_.tid as tid6_3_0_ from T_PRODUCT product0_ where product0_.ID=?Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?西瓜-------------水果
我们 发现 当使用product对象其他属性时向数据库发送查询语句 同时页发送关联对象的查询语句
get方法:
session = HibernateUtil.getSession(); Product p = (Product) session.get(Product.class, 26); System.out.println("---------------"); System.out.println(p.getName()); System.out.println("-------------"); System.out.println(p.getType().getName());
Hibernate: select product0_.ID as ID1_3_0_, product0_.NAME as NAME2_3_0_, product0_.PATH as PATH3_3_0_, product0_.DESCRI as DESCRI4_3_0_, product0_.PRICE as PRICE5_3_0_, product0_.tid as tid6_3_0_ from T_PRODUCT product0_ where product0_.ID=?Hibernate: select type0_.ID as ID1_6_0_, type0_.NAME as NAME2_6_0_ from T_TYPE type0_ where type0_.ID=?---------------西瓜-------------水果在向数据库查询时同时也发送了查询关联对象的SQL语句
多对多关联的延迟加载
teacher 和 student 属于多对多关联
当 lazy="true" 时 会延迟加载,当为false时
<set name="teachers" table="TEACHER_STUDENT" inverse="false" lazy="false" cascade="save-update" > <key column="SID" /> <!-- lazy的值: - true - false - extra --> <many-to-many column="TID" class="com.lgh.hibernate.entity.Teacher"></many-to-many> </set>
session = HibernateUtil.getSession(); Student s = (Student) session.get(Student.class, 1); System.out.println("---------------"); System.out.println(s.getName()); System.out.println("-------------");
Hibernate: select student0_.ID as ID1_4_0_, student0_.NAME as NAME2_4_0_ from T_STUDENT student0_ where student0_.ID=?Hibernate: select teachers0_.SID as SID2_4_0_, teachers0_.TID as TID1_2_0_, teacher1_.ID as ID1_5_1_, teacher1_.NAME as NAME2_5_1_ from TEACHER_STUDENT teachers0_ inner join T_TEACHER teacher1_ on teachers0_.TID=teacher1_.ID where teachers0_.SID=?Hibernate: select students0_.tid as tid1_5_0_, students0_.sid as sid2_2_0_, student1_.ID as ID1_4_1_, student1_.NAME as NAME2_4_1_ from TEACHER_STUDENT students0_ inner join T_STUDENT student1_ on students0_.sid=student1_.ID where students0_.tid=?Hibernate: select students0_.tid as tid1_5_0_, students0_.sid as sid2_2_0_, student1_.ID as ID1_4_1_, student1_.NAME as NAME2_4_1_ from TEACHER_STUDENT students0_ inner join T_STUDENT student1_ on students0_.sid=student1_.ID where students0_.tid=?Hibernate: select teachers0_.SID as SID2_4_0_, teachers0_.TID as TID1_2_0_, teacher1_.ID as ID1_5_1_, teacher1_.NAME as NAME2_5_1_ from TEACHER_STUDENT teachers0_ inner join T_TEACHER teacher1_ on teachers0_.TID=teacher1_.ID where teachers0_.SID=?---------------张华-------------延迟加载已经没有了
一对一的延迟加载
一对一与一对多相同 这里就不再讲述了
<!-- lazy : 三种 值: - false - proxy - no-proxy --> <one-to-one name="person" class="com.lgh.hibernate.entity.Person" cascade="save-update" ></one-to-one>
hibernate的延迟加载就讲到这里 ,有什么错误的地方还请大家指出来
- Hibernate延迟加载分析
- hibernate延迟加载分析
- hibernate延迟加载异常分析(转)
- Hibernate中的延迟加载
- Hibernate延迟加载机制
- Hibernate延迟加载机制
- 再论hibernate延迟加载
- HIBERNATE延迟加载原理
- Hibernate延迟加载机制
- Hibernate延迟加载
- hibernate延迟加载
- hibernate延迟加载
- Hibernate延迟加载机制
- Hibernate延迟加载机制
- Hibernate延迟加载机制
- Hibernate延迟加载机制
- Hibernate延迟加载
- Hibernate属性延迟加载
- git如何与原始仓库同步
- 【Python学习日记】字符编码
- mvvm
- 《LDA漫游指南》数学基础阅读笔记
- 表情识别数据集整理
- hibernate延迟加载分析
- OC基础:Block简介
- jQuery选择器
- JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结
- 【洛谷1025 数的划分】【搜索】
- android binder
- CF_604B(二分+贪心)
- 《疯狂JAVA讲义》——聊天系统(1)
- 《SQL必知必会》16-18章笔记