hibernate之延迟加载(Lazy Loading)

避免在某些情况下,关联关系给我们带来无谓的开销,Hibernate引入了延迟加载的概念;

Hibernate3中的延迟记载可以针对:

  • 实体对象
  • 集合(Collection)
  • 属性的延迟加载

通过Load方法,可以返回目标实体对象的代理;

1,针对实体对象的延迟加载:

在class标签里添加lazy="true",属性:

<class name="TUser" table="t_user" lazy="true">

 如果将lazy="false"时,当程序运行:

TUser user = (TUser) session.load(TUser.class, new Integer(1));

 时,会发出SQL,从数据库中取出所对应的记录,并构造了一个完整的TUser对象;

如果将lazy="true"后,程序执行到:

TUser user = (TUser) session.load(TUser.class, new Integer(1));

 时,并没有任何SQL语句发出,此时对象里的属性也为空,当程序执行到:

System.out.println("user Name:"+users.getName());

 时,可以用Eclipse的Debug看到对象的属性仍然为空,但是看日志输出,会发现已经发出SQL,并也取到了其想要的name名字;

延迟加载和非延迟加载的差异在于Hibernate的代理机制,Hibernate引入了CGLib作为代理机制的实现,也就是我们在DeBug下可以看到TUser$EnhancerByCGLIB$$bede8986类型对象的原因;

CGLIB可以在运行期生成 java Class,这里的代理机制,其基本原理就是通过由CGLIB构造一个包含目标对象所有属性和方法的动态对象(相当于动态构造目标对象的一个子类)返回,并以之作为中介,为目标对象提供更多的特性;

这时,真正的TUser对象,位于代理类的CGLIB$CALLBACK_0.target属性中,当我们调用getName()方法时,实际上调用的是CGLIB$CALLBACK_0.getName()方法,当调用了CGLIB$CALLBACK_0.getName()后,首先会检查 CGLIB$CALLBACK_0.target中是否存在目标对象;如果存在,则调用目标对象的getName方法返回,如果目标对象为空,则发起数据库查询指令,读取记录,构建目标对象并将其设入CGLIB$CALLBACK_0.target。这样,通过一个中间代理,实现数据延迟加载功能,只有当用户真正的调用实体类的取值方法,Hibernate才会去数据库中取值;

2,类型集合的延迟加载

假如我们有个TUser实体对象,这个对象里面有Set<Book> books;属性;在我们获取TUser基本信息的时候,不必要将books一起查出来,这样的话可以给<set />标签添加lazy属性;

<set name="books" cascade="all" lazy="true">

 这样的话,只有我们实际中真正的用到book了,才会去数据库里查询!

3,属性延迟加载

现将其属性设置:

<property name="name" lazy="true"/>

配置了lazy属性之外,还要借助类增强器对二进制Class文件进行强化处理(buildtime bytecode instrumentation)。通过ANT调用Hibernate类增强器对TUser.class文件进行强化处理。脚本如下:

<project name="HibernateSample" default="instrument" basedir=".">
  <property name="lib.dir" value="./lib"/>
  <property name="classes.dir" value="./bin"/>
  
  <path id="lib.class.path">
     <fileset dir="${lib.dir}">
         <include name="**/*.jar"/>
     </fileset>
   
  <target name="instrument">
     <taskdef name="instrument"
         classname="org.hibernate.tool.instrument.InstrumentTask">

        <classpath path="${classes.dir}"/>
        <classpath refid="lib.class.path"/>
     </taskdef>
        
     <instrument verbose="true">
        <fileset dir="${classes.dir}/com.redsaga/hibernate/db/entity">
           <include name="TUser.class"/>
        </fileset>
     </instrument>
  </target>
</project>
 

相关推荐