`
zengshaotao
  • 浏览: 756812 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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.create or replace procedure batchUpdateCustomer(p_age in number) as begin update CUSTOMERS set AGE=AGE+1 where AGE>p_age;  
2.end; 
create or replace procedure batchUpdateCustomer(p_age in number) as begin update CUSTOMERS set AGE=AGE+1 where AGE>p_age;
end;
 

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

 

Java代码
1.tx = session.beginTransaction();  
2.Connection con=session.connection();  
3.String procedure = "{call batchUpdateCustomer(?) }";  
4.CallableStatement cstmt = 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.    update STUDENT set AGE=AGE+1 where AGE>a;  
4.end; 
create or replace produre batchUpdateStudent(a in number) as
begin
    update STUDENT set AGE=AGE+1 where AGE>a;
end;

      调用代码如下:
Java代码
1.Transaction tx=session.beginSession();  
2.Connection conn=session.connection();  
3.String pd=“……{call batchUpdateStudent(?)}”;  
4.CallableStatement cstmt=conn.PrepareCall(pd);  
5.cstmt.setInt(1,20); //把年龄这个参数设为20  
6.tx.commit(); 
Transaction tx=session.beginSession();
Connection conn=session.connection();
String pd=“……{call batchUpdateStudent(?)}”;
CallableStatement cstmt=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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics