《深入浅出hibernate》(4)持久层操作

来源:互联网 发布:c语言能干嘛 编辑:程序博客网 时间:2024/05/01 12:57

               1。首先是Session.load/get两种方法,两者都可以根据指定的实体类和ID从数据库中读取记录,并返回与之对应的实体对象,区别在于:

A。如果未能发现符合条件的记录,get返回null,而load会抛出ObjectNotFoundException

B。load可以返回实体的代理实例(延迟加载实体对象时,hibernate3默认是延迟加载),而get永远返回实体对象本身

C。load方法可以充分利用内部缓存和2级缓存,而get方法则仅仅在内部缓存中查找,如果没有发现,就直接越过2级缓存进行SQL查询。

             2。Session.find/iterate,两个方法在hibernate3中被Query.list()和Query.iterate方法替代。find的方法将从数据库中获取所有符合条件的记录并构造相应实体对象,实体对象构造完毕后,将之纳入缓存,而iterate是执行N+1查询。另一方面,find方法对缓存只写不读,而iterate方法却可以充分利用缓存,在系统只读或者读取比较频繁的情况下,通过iterate可以获得较大的性能。在进行海量信息查询时,最好结合iterate和evict方法逐条对记录进行处理:


  Iterator it = query.iterate();
  while (it.hasNext()) {
   TUser user = (TUser) it.next();
   session.evict(user);
   System.out.println("user name:" + user.getName());
  }

 在实际开发中,对于大批量数据处理,推荐采用SQL或者存储过程。

              3。查询缓存,在hibernate.cfg.xml设置:

<property name="hibernate.cache.use_query_cache">true</property>

在每次进行查询前,设置:

query.setCacheable(true);

查询缓存的作用并未像想象中的那么强大,它仅仅在以下情况发挥作用:

A。完全相同的Select SQL重复执行

B。并且在两次查询之间,对应的库表未发生改变

 

             4。接来就是延迟加载的讨论。在hibernate3中延迟加载默认是true,我在javaeye看到帖子说到这个问题:

<many-to-one>默认的属性是lazy="proxy",此时默认是会延迟加载的.在指定了lazy="true"之后,必须要经过运行期字节码增加,延迟加载才有效果.
而<one-to-one>相对要复杂一点,延迟加载还要受到constrained属性的限制.constrained="false"时表明实体和被关联到的实体的约束不是强制的,即存在一个实体时,它通过<one-to-one>关联的实体可能存在,也可能不存在,这时在查询实体时,Hibernate总会发起一次查询检查<one-to-one>所关联的实体是否存在,而这时已经可以把one-to-one关联的实体查询出来了,因此在<one-to-one>关系中,如果constrained="false",总是会立即加载关联到的实体.
如果当constrained="true",且lazy="proxy"(默认),是可以延迟加载的.
如果当constrained="true",且lazy="true"时,需要经过运行期字节码增加,延迟加载才会奏效.

A。实体对象的延迟加载,此时load到的对象其实是实体对象的代理,我在eclipse的debug窗口对load方法设置了断点观察实体对象,确实是一个代理对象,真正的实体的对象位于代理类的target属性,hibernate是通过CGLIB实现对类的代理。

B。集合的延迟加载,需要注意的如果需要在session关闭之后强制加载关联对象,可以通过Hibernate.initialize()方法。另外,关于关联的对象缓存策略,你除了需要设置集合类型的缓存,还需要设置集合所关联对象的实体的缓存策略。

C。属性的延迟加载,除了属性的lazy声明为true外,还需要借助类增强器对class文件进行强化处理,典型的ant配置文件如下:

project name="hibernate3demo" default="instrument" basedir=".">
   <property name="lib.dir" value="./lib"/>
   <property name="classes.dir" value="./bin"/>
   
  <path id="lib.class.path">

    <!-- The object files for this application -->
    <pathelement location="${classes.dir}"/>

    <!-- The lib files for this application -->
    <fileset dir="${lib.dir}">
      <include name="*.jar"/>
      <include name="*.zip"/>
    </fileset>

    <!-- All files/jars that Tomcat makes available -->
   </path>
   <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/denny_blue/hibernate3demo/bean">
             <include name="TUser.class"/>
          </fileset>
      </instrument>
   </target>
 </project>    

            5。数据的保存。此节主要讨论了save和update方法的执行过程,具体不详述。实际开发中可能更为经常使用SaveOrUpdate()方法

            6。数据的批量导入和批量删除。

A。首先是批量导入,没错,迭代调用save方法。如:

for(int i=0;i<100000;i++){

              TUser user=new TUser();

              user.setName("dennis");

              session.save(user);

  }

可惜的是当越来越多TUser对象被加入内部缓存时,内存终将耗尽,抛出OutOfMemory异常。如何解决?首先可以设置hibernate.jdbc.batch_size来指定每次提交的SQL数量(注:mysql的驱动不支持此参数),另外,定时清空内存:

for(int i=0;i<100000;i++){

              TUser user=new TUser();

              user.setName("dennis");

              session.save(user);

              if(i%25==0){

                         session.flush();

                         session.clear();

              }

  }

B。批量删除:因为ORM需要保持内部缓存和2级缓存中数据与数据库中数据的一致性,所以它需要知道具体删除了哪条数据,也就是说不能仅仅删除数据中的数据。因此hibernate执行批量删除时,会查询出所有符合条件的记录,再对记录进行循环删除。变通方法之一就是提供基于游标的删除操作,如:

ScrollableResults scRes=query.Scroll();

while(scRes.next()){

    TUser user=(TUser)scRes.get(0);

    session.delete(user);

}

另外,hibernate3提供了批量删除和批量更新的操作,不过,仍然无法保证缓存数据的一致性,也就是在批量更新之后,你加载的很可能是过期实体对象,哪怕是用不同的session加载。

String hql="delete TUser";

Query query=session.createQuery(hql);

int ret=query.executeUpdate();

tx.commit();

 



  

             

                         

原创粉丝点击