Hibernate

Hibernate先查询数据,确实要消耗一些时间,但是select只读操作和insert,delete,update这些数据库修改操作在速度上有一个以上的数量级的差距。所以 Hibernate虽然查询数据要多耗时,但是消耗的这点时间影响不是很大,主要是内存消耗的多。而delete的速度,我们知道调节Hibernate的Batch Size可以提供大大提高insert, delete和update的速度。

 Hibernate批量处理其实从性能上考虑,它是很不可取的,浪费了很大的内存。从它的机制上讲,Hibernate它是先把符合条件的数据查出来,放到内存当中,然后再进行操作,实际使用下来性能非常不理想.

总结下来有三种来处理以解决性能问题:

1:绕过Hibernate API ,直接通过 JDBC API 来做,这个方法性能上是比较好的。也是最快的。

2:运用存储过程。(移植性不好)

3:还是用Hibernate API 来进行常规的批量处理,可以也有变,变就变在,我们可以在查找出一定的量的时候,及时的将这些数据做完操作就删掉,session.flush();session.evict(XX对象集); 这样也可以挽救一点性能损失。这个“一定的量”要就要根据实际情况做定量参考了

一般地,Hibernate都是 先查询数据加载到内存,再进行操作,这引发了一定的性能问题。

如果底层数据库(如Oracle)支持存储过程,也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行,速度更加快。在Oracle数据库中可以定义一个名为batchUpdateCustomer()的存储过程,代码如下:

Sql代码

1.createorreplaceprocedurebatchUpdateCustomer(p_ageinnumber)asbeginupdateCUSTOMERSsetAGE=AGE+1whereAGE>p_age;

2.end;

createorreplaceprocedurebatchUpdateCustomer(p_ageinnumber)asbeginupdateCUSTOMERSsetAGE=AGE+1whereAGE>p_age;

end;

 

     以上存储过程有一个参数p_age,代表客户的年龄,应用程序可按照以下方式调用存储过程:

Java代码

1.tx=session.beginTransaction();

2.Connectioncon=session.connection();

3.Stringprocedure="{callbatchUpdateCustomer(?)}";

4.CallableStatementcstmt=con.prepareCall(procedure);

5.cstmt.setInt(1,0);//把年龄参数设为0

6.cstmt.executeUpdate();

7.tx.commit(); 

在项目的开发过程之中,由于项目需求,我们常常需要把大批量的数据插入到数据库。数量级有万级、十万级、百万级、甚至千万级别的。如此数量级别的数据用 Hibernate做插入操作,就可能会发生异常,常见的异常是OutOfMemoryError(内存溢出异常)。

首先,我们简单来回顾一下Hibernate插入操作的机制。Hibernate要对它内部缓存进行维护,当我们执行插入操作时,就会把要操作的对象全部放到自身的内部缓存来进行管理。

谈到Hibernate的缓存,Hibernate有内部缓存与二级缓存之说。由于Hibernate对这两种缓存有着不同的管理机制,对于二级缓存,我们可以对它的大小进行相关配置,而对于内部缓存,Hibernate就采取了“放任自流”的态度了,对它的容量并没有限制。我们做海量数据插入的时候,生成这么多的对象就会被纳入内部缓存(内部缓存是在内存中做缓存的),这样你的系统内存就会一点一点的被蚕食

我们想想如何较好的处理这个问题呢?有的开发条件又必须使用Hibernate来处理,当然有的项目比较灵活,可以去寻求其他的方法。

在这里推荐两种方法:

      (1):优化Hibernate,程序上采用分段插入及时清除缓存的方法。

(2):绕过Hibernate API ,直接通过 JDBC API 来做批量插入,这个方法性能上是最 好的,也是最快的。

对于上述中的方法1,其基本是思路为:优化Hibernate,在配置文件中设置hibernate.jdbc.batch_size参数,来指定每次提交SQL的数量;程序上采用分段插入及时清除缓存的方法(Session实现了异步write-behind,它允许Hibernate显式地写操作的批处理),也就是每插入一定量的数据后及时的把它们从内部缓存中清除掉,释放占用的内存。

      配置hibernate.jdbc.batch_size参数的原因就是尽量少读数据库,hibernate.jdbc.batch_size参数值越大,读数据库的次数越少,速度越快。

hibernate.jdbc.batch_size参数值也可能不是设置得越大越好,从性能角度上讲还有待商榷。这要考虑实际情况,酌情设置

 Hibernate3 发布后,对批量更新/删除操作引入了bulk update/delete,其原理就是通过一条HQL语句完成批量更新/删除操作,很类似JDBC的批量更新/删除操作。在性能上,比Hibernate2的批量更新/删除有很大的提升。

1.create or replace produre batchUpdateStudent(a in number) as 

2.begin

3.updateSTUDENTsetAGE=AGE+1whereAGE>a;

4.end;

createorreplaceprodurebatchUpdateStudent(ainnumber)as

begin

updateSTUDENTsetAGE=AGE+1whereAGE>a;

end;

      调用代码如下:

Java代码

1.Transactiontx=session.beginSession();

2.Connectionconn=session.connection();

3.Stringpd=“……{callbatchUpdateStudent(?)}”;

4.CallableStatementcstmt=conn.PrepareCall(pd);

5.cstmt.setInt(1,20);//把年龄这个参数设为20

6.tx.commit();

Transactiontx=session.beginSession();

Connectionconn=session.connection();

Stringpd=“……{callbatchUpdateStudent(?)}”;

CallableStatementcstmt=conn.PrepareCall(pd);

cstmt.setInt(1,20);//把年龄这个参数设为20

tx.commit();

  观察上面的代码,也是绕过Hibernate API,使用 JDBC API来调用存储过程,使用的还是Hibernate的事务边界。存储过程无疑是提高批量处理性能的一个好方法,直接运行与数据库端,某种程度上讲把批处理的压力转接给了数据库。

http://www.webjx.com/htmldata/2005-11-03/1130976163.html

相关推荐