Hibernate 延迟加载介绍

Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载。Hibernate 通过这种延迟加载来降低系统的内存开销,从而保证 Hibernate 的运行性能。

如果想对实体对象使用延迟加载,必须要在实体的映射配置文件中进行相应的配置,如下所示:
book和user是多对一的关系,一个用户可以有很多书。 根据外键对应。

<hibernate-mapping>
    <class name="com.hibernate.domain.Users" table="users">
        <id name="id" column="ID" type="java.lang.String">
            <generator class="uuid.hex"/>
        </id>
        <set name="Books" inverse="true" cascade="all">
            <key><column name="userId" /></key>
            <one-to-many class="com.hibernate.domain.Books" />
        </set>
        <set name="includedUsers" table="USER_DEPARTMENT" schema="oracleUsername" inverse="true">
            <key column="DEPARTMENT_ID" />
            <many-to-many class="com.hibernate.domain.Users" column="USER_ID" />
        </set>
        <property name="totalCount" type="java.lang.Integer"
            formula="(SELECT COUNT(*) FROM BOOKS WHERE USER_ID = ID)" />
    </class>
    
    <class name="com.hibernate.domain.Books" table="Books">
        <many-to-one name="Users" class="com.hibernate.domain.Users" fetch="select" insert="false" update="false">
            <column name="userId" />
        </many-to-one>
    </class>
</hibernate-mapping>  

通过将class的lazy属性设置为true,来开启实体的延迟加载特性。上面映射文件中 <set.../> 元素里的代码指定了 lazy="true"(对于 <set.../> 元素来说,lazy="true"是默认值),它指定 Hibernate 会延迟加载集合属性里 Books 对象。


private Set Books = new HashSet(0);   
private Set<User> includedUsers = new HashSet<User>(0); 

Users instance = (Users) getSession().get("com.hibernate.Users", id);    
Set Books = instance.getBookes(); 

会把user表中对应的Books记录查询出来,使用延迟检索。得到的是一个set集合。

通过上面介绍可以看出,Hibernate 对于 Set 属性延迟加载关键就在于 PersistentSet 实现类。在延迟加载时,开始 PersistentSet 集合里并不持有任何元素。但 PersistentSet 会持有一个 Hibernate Session,它可以保证当程序需要访问该集合时“立即”去加载数据记录,并装入集合元素。
 
与 PersistentSet 实现类类似的是,Hibernate 还提供了 PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等实现类,它们的功能与 PersistentSet 的功能大致类似。
 
熟悉 Hibernate 集合属性读者应该记得:Hibernate 要求声明集合属性只能用 Set、List、Map、SortedSet、SortedMap 等接口,而不能用 HashSet、ArrayList、HashMap、TreeSet、TreeMap 等实现类,其原因就是因为 Hibernate 需要对集合属性进行延迟加载,而 Hibernate 的延迟加载是依靠 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 来完成的——也就是说,Hibernate 底层需要使用自己的集合实现类来完成延迟加载,因此它要求开发者必须用集合接口、而不是集合实现类来声明集合属性。
 
Hibernate 对集合属性默认采用延迟加载,在某些特殊的情况下,为 <set.../>、<list.../>、<map.../> 等元素设置 lazy="false"属性来取消延迟加载。


默认情况下,Hibernate 也会采用延迟加载来加载关联实体,不管是一对多关联、还是一对一关联、多对多关联,Hibernate 默认都会采用延迟加载。
 
对于关联实体,可以将其分为两种情况:
 (1)关联实体是多个实体时(包括一对多、多对多):此时关联实体将以集合的形式存在,Hibernate将使用PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合来管理延迟加载的实体。这就是前面所介绍的情形。
 (2)关联实体是单个实体时(包括一对一、多对一):当 Hibernate 加载某个实体时,延迟的关联实体将是一个动态生成代理对象。
 
当关联实体是单个实体时,也就是使用 <many-to-one.../> 或 <one-to-one.../> 映射关联实体的情形,这两个元素也可通过 lazy 属性来指定延迟加载。


Hibernate 的延迟加载(lazy load)本质上就是代理模式的应用,我们在过去的岁月里就经常通过代理模式来降低系统的内存开销、提升应用的运行性能。Hibernate 充分利用了代理模式的这种优势,并结合了 Javassist 或 CGLIB 来动态地生成代理对象,这更加增加了代理模式的灵活性,Hibernate 给这种用法一个新名称:延迟加载。无论怎样,充分分析、了解这些开源框架的实现可以更好的感受经典设计模式的优势所在。


你可能感兴趣的:(Hibernate 延迟加载介绍)