Hibernate性能优化之————延迟加载与抓取策略
懒加载【延迟加载】:
主要目的:
为了推迟与数据库交互的时间,提高系统的系能
它是hibernate为提高程序执行效率而提供的一种机制,即只有真正使用该对象的数据才会创建
实现方式:
Hibernate中主要通过代理(proxy)机制来实现延迟加载
延迟加载的具体过程:
Hibernate从数据库获取某一个对象数据时、获取某一个对象的集合属性值时、获取某一个对象所关联的另一个对象时,由于没有使用该对象的数据(除标识符值外),Hibernate并不从数据库加载真正的数据,而只是为该对象创建一个代理对象来代表这个对象,这个对象上的所有属性都为默认值;只有在真正需要使用该对象的数据时才创建这个真实的对象,真正的从数据库中加载它的数据。这样在某些情况下,就可以提高查询效率。
注:Session的load()方法对实体的加载默认采用延迟加载(get()方法默认采用立即加载)。
Hibernate中默认采用延迟加载的情况主要有:
1、 当调用Session上的load()方法加载一个实体时,会采用延迟加载
2、 当Session加载某个实体时,会对这个实体中的集合属性值采用延迟加载
3、 当Session加载某一个实体时,会对这个实体所单端关联(one-to-one , many-to-one)的另一个实体对象采用延迟加载
在Hibernate中想要通过修改配置文件来启用或关闭延迟加载功能的方法有:
1、 在加载单个实体,如果不需要延迟加载,就可以使用Session的get()方法
2、 当Session加载某个实体时,不需要对这个实体中的集合属性值延迟加载、而是要立即加载。这时可以在映射文件中针对这个集合的配置元素(<set>、<bag>、<list>……)添加属性lazy=false
3、 当加载Session加载某个实体时,不需要对这个实体所单端关联的另一个实体对象延迟加载,就可以在映射文件中针对这个单端关联的配置元素(<one-to-one>、<many-to-one>)添加属性lazy=false
返回代理对象【可以理解为一种快捷方式】: User_$$_javassist_7【代理对象是不会为空的】
User user=(User)session.load(clazz,id);
User_$$_javassist_7与User类型不同,为什么没有抛异常?
Hibernate在执行过程中动态的创建了User类的子类User_$$_javassist_7,通过这个子类创建了代理对象
代理对象限制:和代理对象关联的session对象关闭之前使用
S.load()懒加载,并不是立刻去访问数据库,返回的是一个代理对象
通过代理对象访问数据库
User.getName会输出一条插入语句一句查询语句
User.getId();,User.getClass();只输出一条插入语句【不访问数据库也会得到,所有不会让代理对象访问数据库】
单端关联(<one-to-one>、<many-to-one>)上的抓取策略
可以给单端关联的映射元素添加fetch属性。Fetch属性有两个可选值
1、 select:作为默认值,它的策略是当需要使用到关联对象的数据时,另外单独发送一条select语句抓取当前对象的关联对象的数据,即延迟加载
2、 join:它的策略是在同一条SELECT语句使用内连接来获得对象的数据和它的关联对象的数据。此时关联对象的延迟加载失败
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.hbsi.domain">
<!-- 映射持久化类 -->
<class name="Order" table="order">
<!-- 映射对象标识符 -->
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 映射普通属性 -->
<property name="orderNo"/>
<property name="createdTime" column="create_time type="timestamp"/>
<!-- 映射多对一关联,添加fetch属性 -->
<many-to-one name="account" column="account_id" fetch="join" not-null="true"/>
</class>
</hibernate-mapping>
集合属性上的抓取策略:
在属性集合的映射元素上可以添加fetch属性,它有三个可选值
1、 select:作为默认值,它的策略是当需要使用所关联集合的数据时,另外单独发送一天SELECT语句抓取当前对象的关联集合,即延迟加载
2、 join:在同一条SELECT语句使用内连接来获得对象的关联集合,此时关联集合上的lazy会失效
3、 subselect:另外发送一条查询语句(或子查询语句)抓取在前面查询到的所有实体对象的关联集合。这个策略对HQL的查询也起作用
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.hbsi.domain">
<!-- 映射持久化类 -->
<class name="Account" table="account">
<!-- 映射对象标识符 -->
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 映射普通属性 -->
<property name="lginName" column="login_name"/>
<!—用集合来映射一对多关联,并指定fetch属性 -->
<set name=”orderSet” cascade=”all” inverse=”true” fetch=”subselect”>
<key column=”account_id”/>
<one-to-many class=”Order”/>
</set >
</class>
</hibernate-mapping>
一对一的关联关系:
当我们查询的是主对象时,将person和idcard左外连接查询出person对象和idcard对象时,没有懒加载
当我们查询的是从对象时,对于idcard所关联的person对象是懒加载的
Lazy的取值有:false【懒加载功能取消】、proxy【用代理对象】、true
Lazy:指相关联的属性,什么时候去抓取
Fetch:通过什么方式来进行抓取。Selsect二次select语句查询
Join连接查询,lazy属性失效