Hibernate检索优化:
检索即查询。为了减轻DB的访问压力,提高检索效率,Hibernate对检索进行了优化。
所谓检索优化,指的是对查询语句的执行时机进行了细致、严格的把控:并不是代码中一出现查询语句,马上就在后台调用执行select语句。而是在代码中真正需要时才执行select。即将select的执行进行了最大可能的“延迟”。
对对象进行检索的目的是为了将对象加载到内存,让程序使用其数据。所以,对象检索也称为对象加载。根据检索对象的不同,可以将检索优化分为两类: (1)当前对象检索优化 (2)关联对象检索优化
对于不使用优化进行对象检索的过程,称为直接加载;否则称为延迟加载,或懒加载。 延迟加载的底层实现,在Hibernate3.3版本之前使用的是CGLIB生成代理实现的,而3.3版本以后是由javassist代理实现的。若实体类使用final修饰,将无法生成CGLIB代理,即对于3.3版本之前的Hibernate将无法实现延迟加载。考虑到对老版本代码的兼容问题,实体类最好不要使用final修饰。
(1)当前对象检索优化:
对于当前对象进行检索加载,Session中提供了两个方法:get()与load()。 默认情况下,get()为直接加载,而load()为延迟加载。
get()方法的直接加载指,当代码中出现get()时,后台马上会调用执行select语句,将对象直接加载到内存。
load()方法的延迟加载指,当代码中出现load()时,后台并不会马上调用执行select。只有当代码中真正在访问除了主键id属性以外的其它属性时,才会真正执行select语句,即此时才会将对象真正加载到内存。
load()方法默认情况下采用延迟加载策略,但也是可以改变的,可以改为直接加载。在该类映射文件的<class/>标签中有个属性lazy,其默认值为true,即采用延迟加载策略。将其值修改为false,load()的执行也将采用直接加载。
(2)关联对象检索优化:
对于关联对象的检索,也可进行延迟加载的优化。采用何种优化策略,要依据映射文件的配置。映射文件中对于关联对象检索的优化配置属性有两个:lazy、fetch。
lazy与fetch各具有若干值,它们不同值的组合,表示不同的对象加载策略。 根据这两个属性配置位置的不同,又分为两种: (1)多端配置优化 (2)单端配置优化
(1)多端加载优化(在一方对象的映射文件中配置属性):
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 6 <hibernate-mapping package="com.tongji.beans"> 7 <class name="Country"> 8 <id name="cid"> 9 <generator class="native"/> 10 </id> 11 <property name="cname"/> 12 <!-- 左外连接查询,不存在延迟加载问题,也就不存在多端加载优化问题 ,所以不用lazy--> 13 <!-- <set name="ministers" cascade="all" fetch="join"> --> 14 <!-- 普通查询(两表分别查询),不使用延迟加载,则查找当前对象的时候,不管关联对象是否用到,都会一起加载 --> 15 <!-- <set name="ministers" cascade="all" fetch="select" lazy="false"> --> 16 <!-- 普通查询,使用延迟加载,则查找当前对象的时候,不加载关联对象,直到用到关联对象的时候,才会加载关联对象 --> 17 <!-- <set name="ministers" cascade="all" fetch="select" lazy="true"> --> 18 <!-- 普通查询,特别延迟,则查找当前对象的时候,不加载关联对象,并且用到关联对象的时候,能用聚合查询的时候,就不做详情查询 --> 19 <!-- <set name="ministers" cascade="all" fetch="select" lazy="extra"> --> 20 <!-- 补充:子查询,效果同普通查询,其实Hibernate5不支持该策略,但为了兼容以前的版本,对subselect进行了保留 --> 21 <!-- <set name="ministers" cascade="all" fetch="subselect" lazy="extra"> --> 22 <!-- 默认使用,fetch="select" lazy="true"这种格式 --> 23 <set name="ministers" cascade="save-update"> 24 <key column="countryId"/> 25 <one-to-many class="Minister"/> 26 </set> 27 </class> 28 </hibernate-mapping>
测试代码:
1 @Test 2 public void test01() { 3 //1. 获取Session 4 Session session = HbnUtils.getSession(); 5 try { 6 //2. 开启事务 7 session.beginTransaction(); 8 //3. 操作 9 Country country = session.get(Country.class, 1); 10 Set<Minister> ministers = country.getMinisters(); 11 //集合大小的输出 12 System.out.println("ministers.size() = " + ministers.size()); 13 //集合详情的输出 14 System.out.println(ministers); 15 //4. 事务提交 16 session.getTransaction().commit(); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 //5. 事务回滚 20 session.getTransaction().rollback(); 21 } 22 }
(2)单端加载优化(在多方对象的映射文件配置属性):
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 6 <hibernate-mapping package="com.tongji.beans"> 7 <class name="Minister"> 8 <id name="mid"> 9 <generator class="native"/> 10 </id> 11 <property name="mname"/> 12 <!-- 关联属性名 --> 13 <!-- 左外连接查询,同多端加载优化 --> 14 <!-- <many-to-one name="country" cascade="save-update" 15 class="Country" column="countryId" fetch="join"/> --> 16 <!-- 普通查询之直接加载,同多端加载优化 --> 17 <!-- <many-to-one name="country" cascade="save-update" 18 class="Country" column="countryId" fetch="select" lazy="false"/> --> 19 <!-- 普通查询,是否延迟加载,由关联对象的lazy值决定--> 20 <many-to-one name="country" cascade="save-update" 21 class="Country" column="countryId" fetch="select" lazy="proxy"/> 22 <!-- 补充:no-proxy和proxy基本相同,但是会对字节码进行加强 --> 23 <!-- <many-to-one name="country" cascade="save-update" 24 class="Country" column="countryId" fetch="select" lazy="no-proxy"/> --> 25 </class> 26 </hibernate-mapping>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 6 <hibernate-mapping package="com.tongji.beans"> 7 <!-- 单端加载优化,之普通查询,直接加载--> 8 <!-- <class name="Country" lazy="false"> --> 9 <!-- 单端加载优化,之普通查询,延迟加载 ,默认--> 10 <class name="Country" lazy="true"> 11 <id name="cid"> 12 <generator class="native"/> 13 </id> 14 <property name="cname"/> 15 <set name="ministers" cascade="all"> 16 <key column="countryId"/> 17 <one-to-many class="Minister"/> 18 </set> 19 </class> 20 </hibernate-mapping>
测试代码:
1 @Test 2 public void test01() { 3 //1. 获取Session 4 Session session = HbnUtils.getSession(); 5 try { 6 //2. 开启事务 7 session.beginTransaction(); 8 //3. 操作 9 Minister minister = session.get(Minister.class, 2); 10 Country country = minister.getCountry(); 11 12 System.out.println("country.id = " + country.getCid()); 13 System.out.println("country.name = " + country.getCname()); 14 //4. 事务提交 15 session.getTransaction().commit(); 16 } catch (Exception e) { 17 e.printStackTrace(); 18 //5. 事务回滚 19 session.getTransaction().rollback(); 20 } 21 }