一、Hibernate检索策略
1、Hibernate提供了三种检索策略:立即检索策略、延迟检索策略(懒加载机制)、迫切左外连接检索策略。Hibernate在3.x以前lazy属性默认为false,Session的get()方法、load()方法默认都使用的是立即检索策略。从3.x以后,lazy属性为true,get()方法使用的是立即检索策略,load()方法默认使用的延迟检索策略。
以前默认的立即检索策略存在两大不足:
①、select语句的数据太多,需要频繁的访问数据库,会影响检索性能。如果需要检索查询n个Customer对象,那么必须执行n+1次select查询语句。这种检索策略没有利用sql的链接查询功能,例如,以上5条select语句完全可以通过以下一条select语句完成:select * from customer left outer join Orders on customers.id=orders.customer_id
②、在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象白白浪费了许多内存空间。
而HIbernate提供的延迟检索策略能避免多余加载应用程序不需要访问的关联对象,迫切左外连接检索策略则充分利用了sql的外连接查询功能,能够减少select语句的数目。
2、类级别和关联级别的检索策略
检索策略的作用域 | 可选的检索策略 | 默认的检索策略 | 运行时行为受影响的Session的检索方法 |
类级别 |
立即检索 延迟检索 |
立即检索 | 仅影响load()方法 |
关联级别 |
立即检索 延迟检索 迫切左外连接检索 |
多对一和一对一关联为外连接检索 一对多和多对多关联为立即检索 |
影响Load()、get()和find()方法 |
在类级别中,可选的检索策略包括立即检索和延迟检索策略,但是它仅影响load()方法,在关联级别中,可选的检索策略包括立即检索、延迟检索和迫切左外连接检索。
三种检索策略的运行机制:
检索策略类型 | 类级别 | 关联级别 |
立即检索 | 立即加载检索方法指定的对象 |
立即加载与检索方法指定的对象关联的对象。 |
延迟检索 | 延迟加载检索方法指定的对象 | 延迟加载与检索方法指定的对象关联的对象。 |
迫切左外连接检索 | 不适用 | 通过左外连接加载与检索方法指定的对象关联的对象 |
二、类级别的检索策略:
1、类级别可选的检索策略包括立即检索和延迟检索,默认为立即检索。如果<class>元素的lazy属性为true,表示采用延迟检索。如果lazy属性为false,表示采用立即检索。从Hibernate3.x以后,类级别的lazy默认为true,表示load()方法采用延迟检索策略。当执行Session的load()方法时,Hibernate不会立即执行查询CUSTOMER表的select语句,仅仅返回Customer类的代理类的实例,这个代理类有以下特征:
①、由Hibernate在运行时动态生成,它扩展了Customer类,因此它继承了Customer类的所有属性和方法,但它的实现对于应用程序时透明的。
②、当HIbernate创建Customer代理类实例时,仅仅初始化了它的OID属性,其他属性全为null,因此这个代理类实例占用内存很少。
③、当应用程序第一次访问Customer代理类实例时,例如调用Customer.getName()方法,HIbernate会初始化代理类实例,在初始化过程中执行select语句,真正从数据库加载 Customer对象的所有数据。但有个例外,那就是当应用程序访问Customer代理类实例的getId()方法,HIbernate不会初始化代理类实例。
Hibernate类的initialize()静态方法用于在Session范围内显式初始化代理类实例,isInitialize()方法用于判断代理类实例是否已经被初始化。
三、一对多和多对多检索策略
在映射文件中,用<set>元素来配置一对多关联及多对多关联关系。<set>元素有lazy和outer-join属性,
lazy属性 | outer-join属性 | 检索策略 |
false | false | 采用立即检索,这是默认的检索策略 |
false | true | 采用迫切左外连接检索策略 |
true | false | 采用延迟检索策略 |
true | true | 毫无意义 |
HIbernate为Set集合也提供了代理类,它扩展了Set接口,但它的实现对应用程序时透明大的。
<set>元素有一个batch-size属性,用于为延迟检索或立即检索策略设定批量检索数量。批量检索能够减少select语句,提高延迟检索检索或立即检索的性能。
当<set .....batch-size=3>时,HIbernate的select语句,会变为:select * from orders where customer_id=1 or customer_id=2 or customer_id=3。必须根据实际情况确定批量检索数目,合理的批量检索数目应该控制在3到10之间。
outer-join=true属性,设置迫切左外连接检索策略。
四、多对一和一对一关联的检索策略
1、<many-to-one>元素有一个outer-join属性,他有三个可选值:
①、auto:这是默认值,如果Customer.hbm.xml文件的class元素的lazy属性为true,那么对于Order关联的Customer对象采用延迟检索策略。否则采用迫切左外连接检索策略。
②、true。不管Customer.hbm.xml文件的class元素的lazy属性为true还是false,对于Order关联的Customer对象都采用迫切左外连接检索策略。
③、false:始终不会对于ORder关联的Customer对象采用迫切左外连接检索策略。
对于多对一或一对一关联,应该优先考虑使用外连接检索策略,因为它比立即检索策略使用的select数据少,假如应用程序仅仅希望访问ORder对象,并不需要立即访问与ORder对象关联的Customer对象,也可以考虑使用延迟检索策略。
在<one-to-one>一对一关联中,如果使用懒加载机制,必须把<one-to-one>元素中的constrained属性设为true,(constrained属性只能用在一对一关联中)。
五、Hibernate对迫切左外连接检索的限制
假如select语句包含多个一对多关联的外连接,会导致一次检索出大批量的数据,从而影响检索性能,因此Hibernate对迫切左外连接做了限制:
①、在一个select语句中只允许包含一个一对多或多对多关联的迫切左外连接。
②、在一个select语句中允许包含多个多对一或一对一关联的迫切左外连接。