Hibernate的检索(抓取)策略
2013-07-22 09:31
274 查看
1、 建立模拟数据 ---- 建立3个Customer 和 30个Order(每个客户10个订单)
2、 立即检索和延迟检索
立即检索: 立即加载检索方法指定的对象
延迟检索: 延迟加载检索方法指定的对象
hibernate框架检索一个主要优化策略就是延迟检索
get和load 的区别 ?
get默认使用立即检索
load默认使用延迟检索
3、 hibernate 延迟检索中代理对象
load方法返回代理对象 ,默认是目标对象子类对象,对象由 javassist工具包生成
Javassist作用
一个开源的分析、编辑和创建Java字节码的类库(字节码.class文件 ,ClassLoader 类加载器会加载字节码,生成Class对象 )
简单的使用方式
// javassist 修改字节码
// 动态修改方法
ClassPool cp = ClassPool.getDefault(); // 类加载池
CtClass cc = cp.get("cn.itcast.javassist.HelloService"); // 类
CtMethod m = cc.getDeclaredMethod("sayHello"); // 方法
// 在目标方法 sayHello 执行前 增加一段代码
m.insertBefore("{ System.out.println(\"HelloService.sayHello():\"); }");
//将其转换为class类
Class c = cc.toClass();
HelloService helloService2 = (HelloService) c.newInstance();
helloService2.sayHello();
hibernate生成代理对象特点
1) 返回目标类子类对象
2) 在对象存在一个handler,handler 提供了一个initialized的属性值为 false ,id 封装查询对象id,target值null,当访问代理对象id之外的其他属性,就执行查询语句, 初始化后,将 initialized 属性置为true ,target中封装查询结果数据。
手动进行初始化
hibernate框架中 提供工具类 Hibernate类
方法:static void initialize(Object proxy) 对延迟加载代理对象进行初始化
static boolean isInitialized(Objectproxy) 判断延迟加载代理对象是否初始化(数据只需要初始化一次)
4、 区分类级别检索策略和集合级别的检索策略
1) 类级别检索策略
默认 session.load(Customer.class,1) ; 采用延迟检索, 在Customer.hbm.xml 配置 <class> lazy属性来控 制load 可以延迟还是立即检索,如果设置 lazy="false" 的话,load 将采用立即检索,效果等同于 get。 这里说的是否检索customer,就为类级别检索。
2) 关联级别检索策略
当程序已经获得 Customer的持久态对象,customer类中关联 Set<Order>,当需要访问orders订单集合时,采用立即检索还是延迟检索,叫做关联级别的检索 。这里说的是否检索customer中的order,就为关联检索。
默认情况下关联级别检索 使用延迟加载策略,也可以在hbm文件进行配置,控制关联对象是立即还是延迟
5、 类级别的检索策略
类级别可选的检索策略包括立即检索和延迟检索,
默认为延迟检索,对于默认延迟只针对的是load方法
session.get(xxx.class,id) 立即加载
session.load(xxx.class,id) 默认延迟加载
query.list()立即加载
类级别的检索策略可以通过 <class>
元素的 lazy 属性进行设置(配置hbm)
设置hbm文件 <class> 元素 lazy="false" 立即检索策略 (load
方法效果就等同于get了 )
注:Session的get 方法, Query的list方法 默认使用 立即检索,不会受 <class> lazy的影响
6、 关联级别的检索策略
已经查询类级别数据,相关联对象数据检索
例如:已经查询出customer对象,又要查询customer关联的order对象
关联级别的检索分为两部分
第一部分:一对多和多对多元素的关联 (都用set标签,关联的是一个集合对象)
<set>
<one-to-many>/ <many-to-many>
</set>
<set> 元素提供两个属性,共同决定检索策略 lazy和fetch
lazy:决定关联集合对象加载的时机
fetch:决定生成SQL语句形式
* fetch 可以取值有 join、select默认、subselect ;lazy 可以取值有true默认、false、extra
1)当fetch取值为 join时,lazy属性会被忽略(迫切左外连接检索)
fetch为join时,生成左外连接SQL语句
例:select * from customer left outer join orders on customer.id =orders.customer_id ;
备注:内连接是保证两个表中所有的行都要满足连接条件,而外连接则不然。在外连接中,某些不满条件的列也会显示出来,也就是说,只限制其中一个表的行,而不限制另一个表的行。这种连接形式在
许多情况下是非常有用的。外连接只能用于两个表中。
在 Ansi
语法形式中,包含下列三种外连接关键字:
◆Left Outer Join
包含了左表中的全部行(表达式中第一个表)
◆Right Outer Join
包括了右表中的全部行(表达式中第二个表)
◆Full Outer Join
包括了左表和右表中所有不满足条件的行
忽略lazy的原因:当查询出customer时,语句要作为左外连接查询customer,order数据也会被检索出,所以无论lazy取任何值,都会被立即检索。
2) fetch取值为 select
(将采用多条简单SQL语句)
lazy="false"立即检索
lazy="true" 延迟检索
lazy="extra"极其懒惰 (比延迟更加延迟) 增强延迟检索
必须在获得order数据时,才会查询,如果查询order记录数量会用到count(*),而不用对象查询
3) fetch取值为 subselect (将采用子查询方式产生SQL语句)
lazy="false"立即检索
lazy="true" 延迟检索
lazy="extra"极其懒惰 (增强延迟检索)
注意问题 :
1、使用延迟检索的时候
当设置 <set> lazy="true"时,Hibernate 在以下情况下初始化集合代理类实例。
• 应用程序第一次访问集合属性: iterator(), size(), isEmpty(),contains() 等方法
• 通过 Hibernate.initialize() 静态方法进行显式初始化
2、使用增强延迟检索的时候
主要区别是增强延迟检索策略能进一步延迟 Customer对象的 orders
集合代理实例的初始化时机
当设置 <set> lazy="extra"时,Hibernate 在以下情况下初始化集合代理类实例。
• 当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders集合代理类实例的初始化
• 当程序第一次访问 order 属性的 size(), contains() 和 isEmpty()方法时, Hibernate 不会初始化orders 集合类的实例,
仅通过特定的 select 语句查询必要的信息,
不会检索所有的 Order
对象。
3、案例中,使用get/load查询customer时,配置fetch="join" 采用迫切左外连接查询,order会被查询,采用立即检索 lazy被忽略,但是如果使用Query的list方法查询时,hibernate不会自动生成sql语句了,他要根据手动编写的HQL语句生成SQL语句,因此对于fetch="join"的左外连接语句就会被忽略不起作用了,这是的lazy属性就重新生效了。
第二部分 :多对一和一对一元素关联(关联的是一个实体对象)
<many-to-one>/ <one-to-one>
也是由两个属性决定 fetch
和 lazy
fetch:决定SQL语句形式,
lazy:决定加载时间
fetch有两个取值 join 和 select ; lazy 有三个取值 false 、proxy 、no-proxy
1) 当fetch
取值 join
,采用迫切左外连接 lazy
被忽略(与关联集合一样)
针对 get/load 有效
如果Query,fetch="join" 被忽略,lazy 将重新生效
2) 当fetch取值 select
,产生多条SQL
查询
lazy="false"采用立即查询
lazy="proxy" 将由Customer.hbm.xml的<class>中的lazy属性决定是延迟还是立即(由对方类级别检索策略决定)
案例分析练习一
many2one立即检索+set立即检索
案例分析练习二
many2one迫切左外+set立即检索
案例分析练习三
many2one立即检索+set迫切左外
批量检索查询优化(N+1
问题解决)
1、从一的一端 进行批量检索
N+1 问题:查询每个客户的订单,如果10000个客户,会产生 10001 条SQL,其中1条为查询出所有的客 户,另外的10000条都是一样的sql,都是查询订单表中customer_id=?,所以会产生多条相同 的sql。
解决方法:在<set>中配置batch-size
属性,表示一次查询几个客户的订单(配置在Customer.hbm.xml)
例如 :10000 个客户,如果设置 batch-size="10",那么就会产生 1001条SQL,其中每十个客户用了同一条sql,当然也可以配置为10000,这样就只有两条sql了,就得到了优化。实际上是将sql语句写成了这样:select
* from order where oreder.customer_idin(?,?,?.....);
2、 从多的一端进行批量检索
问题:查询每个订单客户的姓名
产生4条SQL,一条查询订单,三条查询三个客户(订单关联的客户是重复的,前十个订单关联一个客户,只要查询出一个客户后,就会放人一级缓存了,下次再查询就直接获取了,不用编写sql进行查询了), 配置一次多查询几个客户 (配置Customer.hbm.xml)
解决方法:在Customer的hbm文件中的class中配置batch-size
<class name="cn.itcast.domain.fetch.Customer"table="customer" catalog="hibernate3day3"lazy="true" batch-size="2">
小结:在实际开发中,优先使用延迟加载策略(提高性能),但是延迟加载有重要问题,延迟加载返回的是
代理对象,代理对象要想加载延迟的数据,Session就不能close,如果连接关闭了就不能再初始化延
迟的代理对象了。如果在session关闭后再进行初始化的话就会抛出如下异常
org.hibernate.LazyInitializationException:failed to lazily initialize a collection of role:cn.itcast.domain.fetch.Customer.orders, no session or session was closed
2、 立即检索和延迟检索
立即检索: 立即加载检索方法指定的对象
延迟检索: 延迟加载检索方法指定的对象
hibernate框架检索一个主要优化策略就是延迟检索
get和load 的区别 ?
get默认使用立即检索
load默认使用延迟检索
3、 hibernate 延迟检索中代理对象
load方法返回代理对象 ,默认是目标对象子类对象,对象由 javassist工具包生成
Javassist作用
一个开源的分析、编辑和创建Java字节码的类库(字节码.class文件 ,ClassLoader 类加载器会加载字节码,生成Class对象 )
简单的使用方式
// javassist 修改字节码
// 动态修改方法
ClassPool cp = ClassPool.getDefault(); // 类加载池
CtClass cc = cp.get("cn.itcast.javassist.HelloService"); // 类
CtMethod m = cc.getDeclaredMethod("sayHello"); // 方法
// 在目标方法 sayHello 执行前 增加一段代码
m.insertBefore("{ System.out.println(\"HelloService.sayHello():\"); }");
//将其转换为class类
Class c = cc.toClass();
HelloService helloService2 = (HelloService) c.newInstance();
helloService2.sayHello();
hibernate生成代理对象特点
1) 返回目标类子类对象
2) 在对象存在一个handler,handler 提供了一个initialized的属性值为 false ,id 封装查询对象id,target值null,当访问代理对象id之外的其他属性,就执行查询语句, 初始化后,将 initialized 属性置为true ,target中封装查询结果数据。
手动进行初始化
hibernate框架中 提供工具类 Hibernate类
方法:static void initialize(Object proxy) 对延迟加载代理对象进行初始化
static boolean isInitialized(Objectproxy) 判断延迟加载代理对象是否初始化(数据只需要初始化一次)
4、 区分类级别检索策略和集合级别的检索策略
1) 类级别检索策略
默认 session.load(Customer.class,1) ; 采用延迟检索, 在Customer.hbm.xml 配置 <class> lazy属性来控 制load 可以延迟还是立即检索,如果设置 lazy="false" 的话,load 将采用立即检索,效果等同于 get。 这里说的是否检索customer,就为类级别检索。
2) 关联级别检索策略
当程序已经获得 Customer的持久态对象,customer类中关联 Set<Order>,当需要访问orders订单集合时,采用立即检索还是延迟检索,叫做关联级别的检索 。这里说的是否检索customer中的order,就为关联检索。
默认情况下关联级别检索 使用延迟加载策略,也可以在hbm文件进行配置,控制关联对象是立即还是延迟
5、 类级别的检索策略
类级别可选的检索策略包括立即检索和延迟检索,
默认为延迟检索,对于默认延迟只针对的是load方法
session.get(xxx.class,id) 立即加载
session.load(xxx.class,id) 默认延迟加载
query.list()立即加载
类级别的检索策略可以通过 <class>
元素的 lazy 属性进行设置(配置hbm)
设置hbm文件 <class> 元素 lazy="false" 立即检索策略 (load
方法效果就等同于get了 )
注:Session的get 方法, Query的list方法 默认使用 立即检索,不会受 <class> lazy的影响
6、 关联级别的检索策略
已经查询类级别数据,相关联对象数据检索
例如:已经查询出customer对象,又要查询customer关联的order对象
关联级别的检索分为两部分
第一部分:一对多和多对多元素的关联 (都用set标签,关联的是一个集合对象)
<set>
<one-to-many>/ <many-to-many>
</set>
<set> 元素提供两个属性,共同决定检索策略 lazy和fetch
lazy:决定关联集合对象加载的时机
fetch:决定生成SQL语句形式
* fetch 可以取值有 join、select默认、subselect ;lazy 可以取值有true默认、false、extra
1)当fetch取值为 join时,lazy属性会被忽略(迫切左外连接检索)
fetch为join时,生成左外连接SQL语句
例:select * from customer left outer join orders on customer.id =orders.customer_id ;
备注:内连接是保证两个表中所有的行都要满足连接条件,而外连接则不然。在外连接中,某些不满条件的列也会显示出来,也就是说,只限制其中一个表的行,而不限制另一个表的行。这种连接形式在
许多情况下是非常有用的。外连接只能用于两个表中。
在 Ansi
语法形式中,包含下列三种外连接关键字:
◆Left Outer Join
包含了左表中的全部行(表达式中第一个表)
◆Right Outer Join
包括了右表中的全部行(表达式中第二个表)
◆Full Outer Join
包括了左表和右表中所有不满足条件的行
忽略lazy的原因:当查询出customer时,语句要作为左外连接查询customer,order数据也会被检索出,所以无论lazy取任何值,都会被立即检索。
2) fetch取值为 select
(将采用多条简单SQL语句)
lazy="false"立即检索
lazy="true" 延迟检索
lazy="extra"极其懒惰 (比延迟更加延迟) 增强延迟检索
必须在获得order数据时,才会查询,如果查询order记录数量会用到count(*),而不用对象查询
3) fetch取值为 subselect (将采用子查询方式产生SQL语句)
lazy="false"立即检索
lazy="true" 延迟检索
lazy="extra"极其懒惰 (增强延迟检索)
注意问题 :
1、使用延迟检索的时候
当设置 <set> lazy="true"时,Hibernate 在以下情况下初始化集合代理类实例。
• 应用程序第一次访问集合属性: iterator(), size(), isEmpty(),contains() 等方法
• 通过 Hibernate.initialize() 静态方法进行显式初始化
2、使用增强延迟检索的时候
主要区别是增强延迟检索策略能进一步延迟 Customer对象的 orders
集合代理实例的初始化时机
当设置 <set> lazy="extra"时,Hibernate 在以下情况下初始化集合代理类实例。
• 当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders集合代理类实例的初始化
• 当程序第一次访问 order 属性的 size(), contains() 和 isEmpty()方法时, Hibernate 不会初始化orders 集合类的实例,
仅通过特定的 select 语句查询必要的信息,
不会检索所有的 Order
对象。
3、案例中,使用get/load查询customer时,配置fetch="join" 采用迫切左外连接查询,order会被查询,采用立即检索 lazy被忽略,但是如果使用Query的list方法查询时,hibernate不会自动生成sql语句了,他要根据手动编写的HQL语句生成SQL语句,因此对于fetch="join"的左外连接语句就会被忽略不起作用了,这是的lazy属性就重新生效了。
第二部分 :多对一和一对一元素关联(关联的是一个实体对象)
<many-to-one>/ <one-to-one>
也是由两个属性决定 fetch
和 lazy
fetch:决定SQL语句形式,
lazy:决定加载时间
fetch有两个取值 join 和 select ; lazy 有三个取值 false 、proxy 、no-proxy
1) 当fetch
取值 join
,采用迫切左外连接 lazy
被忽略(与关联集合一样)
针对 get/load 有效
如果Query,fetch="join" 被忽略,lazy 将重新生效
2) 当fetch取值 select
,产生多条SQL
查询
lazy="false"采用立即查询
lazy="proxy" 将由Customer.hbm.xml的<class>中的lazy属性决定是延迟还是立即(由对方类级别检索策略决定)
案例分析练习一
many2one立即检索+set立即检索
案例分析练习二
many2one迫切左外+set立即检索
案例分析练习三
many2one立即检索+set迫切左外
批量检索查询优化(N+1
问题解决)
1、从一的一端 进行批量检索
N+1 问题:查询每个客户的订单,如果10000个客户,会产生 10001 条SQL,其中1条为查询出所有的客 户,另外的10000条都是一样的sql,都是查询订单表中customer_id=?,所以会产生多条相同 的sql。
解决方法:在<set>中配置batch-size
属性,表示一次查询几个客户的订单(配置在Customer.hbm.xml)
例如 :10000 个客户,如果设置 batch-size="10",那么就会产生 1001条SQL,其中每十个客户用了同一条sql,当然也可以配置为10000,这样就只有两条sql了,就得到了优化。实际上是将sql语句写成了这样:select
* from order where oreder.customer_idin(?,?,?.....);
2、 从多的一端进行批量检索
问题:查询每个订单客户的姓名
产生4条SQL,一条查询订单,三条查询三个客户(订单关联的客户是重复的,前十个订单关联一个客户,只要查询出一个客户后,就会放人一级缓存了,下次再查询就直接获取了,不用编写sql进行查询了), 配置一次多查询几个客户 (配置Customer.hbm.xml)
解决方法:在Customer的hbm文件中的class中配置batch-size
<class name="cn.itcast.domain.fetch.Customer"table="customer" catalog="hibernate3day3"lazy="true" batch-size="2">
小结:在实际开发中,优先使用延迟加载策略(提高性能),但是延迟加载有重要问题,延迟加载返回的是
代理对象,代理对象要想加载延迟的数据,Session就不能close,如果连接关闭了就不能再初始化延
迟的代理对象了。如果在session关闭后再进行初始化的话就会抛出如下异常
org.hibernate.LazyInitializationException:failed to lazily initialize a collection of role:cn.itcast.domain.fetch.Customer.orders, no session or session was closed
相关文章推荐
- hibernate_抓取策略-检索配置
- Hibernate检索策略(抓取策略)(Hibernate检索优化)
- 框架 day33 Hibernate,组件映射,继承映射,抓取(检索)策略-优化,检索方式总结
- JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题
- Hibernate检索(抓取)策略
- Hibernate检索策略学习之--预先抓取
- JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题
- hibernate的检索策略(抓取策略)
- hiebernate 学习之六(hibernate的检索策略)
- Hibernate 检索策略 lazy fetch batch-size
- hibernate检索方式与检索策略
- Hibernate三种检索策略的优缺点对比
- Hibernate的检索策略
- [原创]java WEB学习笔记91:Hibernate学习之路-- -HQL 迫切左外连接,左外连接,迫切内连接,内连接,关联级别运行时的检索策略 比较。理论,在于理解
- Hibernate 的检索策略
- Hibernate学习44 -- 抓取策略4 -- 批量抓取(Batch fetching)
- Hibernate配置---检索策略
- 16、【转】Hibernate 原汁原味的四种抓取策略
- 比较Hibernate的三种检索策略优缺点
- Hibernate(八):检索策略