转:
http://java.ccidnet.com/art/3539/20070802/1164285_1.html
在Hibernate中处理批量更新和批量删除
发布时间:2007.08.03 06:06 来源:赛迪网 作者:dxaw
批量更新是指在一个事务中更新大批量数据,批量删除是指在一个事务中删除大批量数据。以下程序直接通过Hibernate API批量更新CUSTOMERS表中年龄大于零的所有记录的AGE字段:
tx = session.beginTransaction();
Iterator customers=session.find("from Customer c where c.age>0").iterator();
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
}
tx.commit();
session.close();
如果CUSTOMERS表中有1万条年龄大于零的记录,那么Session的find()方法会一下子加载1万个Customer对象到内存。当执行tx.commit()方法时,会清理缓存,Hibernate执行1万条更新CUSTOMERS表的update语句:
update CUSTOMERS set AGE=? …. where ID=i;
update CUSTOMERS set AGE=? …. where ID=j;
……
update CUSTOMERS set AGE=? …. where ID=k;
以上批量更新方式有两个缺点:
(1) 占用大量内存,必须把1万个Customer对象先加载到内存,然后一一更新它们。
(2) 执行的update语句的数目太多,每个update语句只能更新一个Customer对象,必须通过1万条update语句才能更新一万个Customer对象,频繁的访问数据库,会大大降低应用的性能。
为了迅速释放1万个Customer对象占用的内存,可以在更新每个Customer对象后,就调用Session的evict()方法立即释放它的内存:
tx = session.beginTransaction();
Iterator customers=session.find("from Customer c where c.age>0").iterator();
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
session.flush();
session.evict(customer);
}
tx.commit();
session.close();
在以上程序中,修改了一个Customer对象的age属性后,就立即调用Session的 flush()方法和evict()方法,flush()方法使Hibernate立刻根据这个Customer对象的状态变化同步更新数据库,从而立即执行相关的update语句;evict()方法用于把这个Customer对象从缓存中清除出去,从而及时释放它占用的内存。
但evict()方法只能稍微提高批量操作的性能,因为不管有没有使用evict()方法,Hibernate都必须执行1万条update语句,才能更新1万个Customer对象,这是影响批量操作性能的重要因素。假如Hibernate能直接执行如下SQL语句:
update CUSTOMERS set AGE=AGE+1 where AGE>0;
那么以上一条update语句就能更新CUSTOMERS表中的1万条记录。但是Hibernate并没有直接提供执行这种update语句的接口。应用程序必须绕过Hibernate API,直接通过JDBC API来执行该SQL语句:
tx = session.beginTransaction();
Connection con=session.connection();
PreparedStatement stmt=con.prepareStatement("update CUSTOMERS set AGE=AGE+1 "
+"where AGE>0 ");
stmt.executeUpdate();
tx.commit();
以上程序演示了绕过Hibernate API,直接通过JDBC API访问数据库的过程。应用程序通过Session的connection()方法获得该Session使用的数据库连接,然后通过它创建 PreparedStatement对象并执行SQL语句。值得注意的是,应用程序仍然通过Hibernate的Transaction接口来声明事务边界。
如果底层数据库(如Oracle)支持存储过程,也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行,速度更加快。在Oracle数据库中可以定义一个名为batchUpdateCustomer()的存储过程,代码如下:
create or replace procedure batchUpdateCustomer(p_age in number) as
begin
update CUSTOMERS set AGE=AGE+1 where AGE>p_age;
end;
以上存储过程有一个参数p_age,代表客户的年龄,应用程序可按照以下方式调用存储过程:
tx = session.beginTransaction();
Connection con=session.connection();
String procedure = "{call batchUpdateCustomer(?) }";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0); //把年龄参数设为0
cstmt.executeUpdate();
tx.commit();
从上面程序看出,应用程序也必须绕过Hibernate API,直接通过JDBC API来调用存储过程。
Session的各种重载形式的update()方法都一次只能更新一个对象,而delete()方法的有些重载形式允许以HQL语句作为参数,例如:
session.delete("from Customer c where c.age>0");
如果CUSTOMERS表中有1万条年龄大于零的记录,那么以上代码能删除一万条记录。但是Session的delete()方法并没有执行以下delete语句:
delete from CUSTOMERS where AGE>0;
Session的delete()方法先通过以下select语句把1万个Customer对象加载到内存中:
select * from CUSTOMERS where AGE>0;
接下来执行一万条delete语句,逐个删除Customer对象:
delete from CUSTOMERS where ID=i;
delete from CUSTOMERS where ID=j;
……
delete from CUSTOMERS where ID=k;
由此可见,直接通过Hibernate API进行批量更新和批量删除都不值得推荐。而直接通过JDBC API执行相关的SQL语句或调用相关的存储过程,是批量更新和批量删除的最佳方式,这两种方式都有以下优点:
(1) 无需把数据库中的大批量数据先加载到内存中,然后逐个更新或修改它们,因此不会消耗大量内存。
(2) 能在一条SQL语句中更新或删除大批量的数据。
分享到:
相关推荐
例如,如果用户实体被删除时,希望其关联的所有组也被删除,则可以在映射文件中设置级联属性为 `cascade="delete"`。 #### 4. unsaved-value (可选 - 默认为 null) 此属性用于指定一个未保存状态的值。如果实体的...
5.1.5 控制insert和update语句 5.2 处理SQL引用标识符 5.3 创建命名策略 5.4 设置数据库Schema 5.5 设置类的包名 5.6 运行本章的范例程序 5.7 小结 5.8 思考题 第6章 映射对象标识符 6.1 关系...
- **`insert-before-update`**:设置为`true`时,在执行更新操作前先执行一次查询操作来判断数据是否真的发生了变化,默认为`false`。 - **`polymorphism`**:多态查询方式,默认为`implicit`。 - **`where`**:指定...
在Web开发中,处理用户上传的图片是一项常见的需求。本文档将详细介绍如何利用Hibernate框架将图片数据直接存储到数据库的Blob字段中。通过这种方式,可以避免在文件系统和数据库之间进行额外的数据传输,从而提高...
在Hibernate中,有两种主要的配置文件形式:`hibernate.cfg.xml` 和 `hibernate.properties`。 1. **`hibernate.cfg.xml`**: - 这种配置文件通常包含数据库连接信息、映射文件位置以及其他配置参数。 - 可以直接...
5.1.5 控制insert和update语句 5.2 处理SQL引用标识符 5.3 创建命名策略 5.4 设置数据库Schema 5.5 设置类的包名 5.6 运行本章的范例程序 5.7 小结 5.8 思考题 第6章 映射对象标识符 6.1 关系...
5.1.5 控制insert和update语句 5.2 处理SQL引用标识符 5.3 创建命名策略 5.4 设置数据库Schema 5.5 设置类的包名 5.6 运行本章的范例程序 5.7 小结 5.8 思考题 第6章 映射对象标识符 6.1 关系...
5.1.5 控制insert和update语句 5.2 处理SQL引用标识符 5.3 创建命名策略 5.4 设置数据库Schema 5.5 设置类的包名 5.6 运行本章的范例程序 5.7 小结 5.8 思考题 第6章 映射对象标识符 6.1 关系...
- 如果启用了延迟加载,但在某个时刻需要加载所有相关对象时,可以通过`fetchSize`和`batchSize`控制批量加载的数量。 #### 十三、Spring事务管理 - **Spring事务管理**: - 推荐使用Spring的容器管理事务,以...
在4.2.20.Final版本中,Hibernate进行了性能优化,如延迟加载(Lazy Loading)、批处理(Batch Processing)、预加载(Preloading)等,以减少数据库访问次数,提升应用性能。 七、事件监听器 Hibernate允许开发者...
SpringBoot JdbcTemplate批量操作是提高数据处理效率的重要手段,尤其在处理大量数据插入或更新时。JdbcTemplate作为Spring框架的一部分,提供了便捷且安全的数据库访问方式,它简化了JDBC的使用,避免了手动管理...
1. 插入/更新:使用Session的save()或update()方法,Hibernate会自动生成相应的INSERT或UPDATE SQL。 2. 删除:调用Session的delete()方法,对应DELETE SQL。 3. 查询:通过Query或Criteria API进行,如: ```java ...
在“异常处理和JDBC”这个主题中,我们将深入探讨JDBC在处理程序错误和异常方面的最佳实践,以及如何结合使用Java的异常处理机制来确保数据库操作的健壮性。 1. **异常处理**:在Java中,异常是程序运行时发生的...
在MySQL数据库中,批量增加数据通常涉及三种主要的方法:JDBC、JdbcTemplate和Hibernate。本文将分析这三种方法的性能,并提供相应的代码示例。 首先,我们来看JDBC。JDBC(Java Database Connectivity)是Java中与...
8. DML操作:包含数据操作命令的使用,如插入(Insert)、更新(Update)、删除(Delete)以及批量操作(Batch support in DML clauses)。 9. 类生成和自定义类型:提供关于如何生成Bean类和使用自定义类型的指导。...
3. **批处理操作**:如果需要批量执行SQL语句,工具类可能还提供`batchUpdate(String[] sqls)`方法,一次处理多条SQL。 4. **关闭连接**:`close()`方法用于关闭数据库连接,释放资源。 在实际应用中,为了确保...
- 对于批量插入或更新,Spring JDBC提供了`batchUpdate()`方法,可以有效地提高性能。 5. **异常处理**: - Spring JDBC将JDBC的异常转换为Spring的`DataAccessException`家族,使得异常处理更加统一和简单。 6....
例如,`JdbcTemplate`的`batchUpdate()`方法可以用于批量执行SQL语句。 9. **异常处理** Spring提供了统一的异常处理机制,将数据库异常转换为Spring的`DataAccessException`子类,简化了异常的捕获和处理。 10. ...
例如,用户上传CSV文件,Controller层接收文件,Service层解析文件内容并调用DAO的批处理方法,如batchUpdate(),将数据导入到数据库。 4. **异常处理**:SpringMVC提供了全局异常处理机制,通过@ControllerAdvice...