﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Energy of Love-随笔分类-Hibernate</title><link>http://www.blogjava.net/titanaly/category/39908.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 16 Jul 2009 11:55:36 GMT</lastBuildDate><pubDate>Thu, 16 Jul 2009 11:55:36 GMT</pubDate><ttl>60</ttl><item><title>[转]在Hibernate中处理批量更新和批量删除 hibernate batch update and insert</title><link>http://www.blogjava.net/titanaly/archive/2009/06/24/283935.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 24 Jun 2009 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/06/24/283935.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/283935.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/06/24/283935.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/283935.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/283935.html</trackback:ping><description><![CDATA[转：<a href="http://java.ccidnet.com/art/3539/20070802/1164285_1.html" target="_blank">http://java.ccidnet.com/art/3539/20070802/1164285_1.html</a> <br />
在Hibernate中处理批量更新和批量删除 <br />
发布时间：2007.08.03 06:06&nbsp;&nbsp;&nbsp;&nbsp; 来源：赛迪网&nbsp;&nbsp;&nbsp; 作者：dxaw <br />
<br />
批量更新是指在一个事务中更新大批量数据，批量删除是指在一个事务中删除大批量数据。以下程序直接通过Hibernate API批量更新CUSTOMERS表中年龄大于零的所有记录的AGE字段： <br />
<br />
tx = session.beginTransaction(); <br />
Iterator customers=session.find("from Customer c where c.age&gt;0").iterator(); <br />
while(customers.hasNext()){ <br />
Customer customer=(Customer)customers.next(); <br />
customer.setAge(customer.getAge()+1); <br />
} <br />
<br />
tx.commit(); <br />
session.close(); <br />
<br />
如果CUSTOMERS表中有1万条年龄大于零的记录，那么Session的find()方法会一下子加载1万个Customer对象到内存。当执行tx.commit()方法时，会清理缓存，Hibernate执行1万条更新CUSTOMERS表的update语句： <br />
<br />
update CUSTOMERS set AGE=? &#8230;. where ID=i; <br />
update CUSTOMERS set AGE=? &#8230;. where ID=j; <br />
&#8230;&#8230; <br />
update CUSTOMERS set AGE=? &#8230;. where ID=k; <br />
<br />
以上批量更新方式有两个缺点： <br />
<br />
(1) 占用大量内存，必须把1万个Customer对象先加载到内存，然后一一更新它们。 <br />
<br />
(2) 执行的update语句的数目太多，每个update语句只能更新一个Customer对象，必须通过1万条update语句才能更新一万个Customer对象，频繁的访问数据库，会大大降低应用的性能。 <br />
<br />
为了迅速释放1万个Customer对象占用的内存，可以在更新每个Customer对象后，就调用Session的evict()方法立即释放它的内存： <br />
<br />
tx = session.beginTransaction(); <br />
Iterator customers=session.find("from Customer c where c.age&gt;0").iterator(); <br />
while(customers.hasNext()){ <br />
Customer customer=(Customer)customers.next(); <br />
customer.setAge(customer.getAge()+1); <br />
session.flush(); <br />
session.evict(customer); <br />
} <br />
<br />
tx.commit(); <br />
session.close(); <br />
<br />
在以上程序中，修改了一个Customer对象的age属性后，就立即调用Session的 flush()方法和evict()方法，flush()方法使Hibernate立刻根据这个Customer对象的状态变化同步更新数据库，从而立即执行相关的update语句；evict()方法用于把这个Customer对象从缓存中清除出去，从而及时释放它占用的内存。 <br />
<br />
但evict()方法只能稍微提高批量操作的性能，因为不管有没有使用evict()方法，Hibernate都必须执行1万条update语句，才能更新1万个Customer对象，这是影响批量操作性能的重要因素。假如Hibernate能直接执行如下SQL语句： <br />
<br />
update CUSTOMERS set AGE=AGE+1 where AGE&gt;0; <br />
<br />
那么以上一条update语句就能更新CUSTOMERS表中的1万条记录。但是Hibernate并没有直接提供执行这种update语句的接口。应用程序必须绕过Hibernate API，直接通过JDBC API来执行该SQL语句： <br />
<br />
tx = session.beginTransaction(); <br />
<br />
Connection con=session.connection(); <br />
PreparedStatement stmt=con.prepareStatement("update CUSTOMERS set AGE=AGE+1 " <br />
+"where AGE&gt;0 "); <br />
stmt.executeUpdate(); <br />
<br />
tx.commit(); <br />
<br />
以上程序演示了绕过Hibernate API，直接通过JDBC API访问数据库的过程。应用程序通过Session的connection()方法获得该Session使用的数据库连接，然后通过它创建 PreparedStatement对象并执行SQL语句。值得注意的是，应用程序仍然通过Hibernate的Transaction接口来声明事务边界。 <br />
<br />
如果底层数据库（如Oracle）支持存储过程，也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行，速度更加快。在Oracle数据库中可以定义一个名为batchUpdateCustomer()的存储过程，代码如下： <br />
<br />
create or replace procedure batchUpdateCustomer(p_age in number) as <br />
begin <br />
update CUSTOMERS set AGE=AGE+1 where AGE&gt;p_age; <br />
end; <br />
<br />
以上存储过程有一个参数p_age，代表客户的年龄，应用程序可按照以下方式调用存储过程： <br />
<br />
tx = session.beginTransaction(); <br />
Connection con=session.connection(); <br />
<br />
String procedure = "{call batchUpdateCustomer(?) }"; <br />
CallableStatement cstmt = con.prepareCall(procedure); <br />
cstmt.setInt(1,0); //把年龄参数设为0 <br />
cstmt.executeUpdate(); <br />
tx.commit(); <br />
<br />
从上面程序看出，应用程序也必须绕过Hibernate API，直接通过JDBC API来调用存储过程。 <br />
<br />
Session的各种重载形式的update()方法都一次只能更新一个对象，而delete()方法的有些重载形式允许以HQL语句作为参数，例如： <br />
<br />
session.delete("from Customer c where c.age&gt;0"); <br />
<br />
如果CUSTOMERS表中有1万条年龄大于零的记录，那么以上代码能删除一万条记录。但是Session的delete()方法并没有执行以下delete语句： <br />
<br />
delete from CUSTOMERS where AGE&gt;0; <br />
<br />
Session的delete()方法先通过以下select语句把1万个Customer对象加载到内存中： <br />
<br />
select * from CUSTOMERS where AGE&gt;0; <br />
<br />
接下来执行一万条delete语句，逐个删除Customer对象： <br />
<br />
delete from CUSTOMERS where ID=i; <br />
delete from CUSTOMERS where ID=j; <br />
&#8230;&#8230; <br />
delete from CUSTOMERS where ID=k; <br />
<br />
由此可见，直接通过Hibernate API进行批量更新和批量删除都不值得推荐。而直接通过JDBC API执行相关的SQL语句或调用相关的存储过程，是批量更新和批量删除的最佳方式，这两种方式都有以下优点： <br />
<br />
(1) 无需把数据库中的大批量数据先加载到内存中，然后逐个更新或修改它们，因此不会消耗大量内存。 <br />
<br />
(2) 能在一条SQL语句中更新或删除大批量的数据。
 <img src ="http://www.blogjava.net/titanaly/aggbug/283935.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-06-24 14:45 <a href="http://www.blogjava.net/titanaly/archive/2009/06/24/283935.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>