Hibernate完全以面向对象的方式操作数据库,当程序员以面向对象的方式操作持久化对象时,将自动转换为对数据的操作。例如我们Session的delete()方法,来删除持久化对象,Hibernate将负责删除对应的数据记录;当我们执行持久化对象的setter方法时,Hibernate将自动转换为底层的update语句,修改数据库的对应记录。

  问题是:如果我们需要同时更新100000条记录,是不是要逐一加载100000条记录,然后依次调用setter方法——这样不仅繁琐,数据访问的性能也十分糟糕。为了面对这种批量处理的场景,Hibernate提供了批量处理的解决方案。下面分别从批量插入,批量更新和批量删除三个方面介绍如何面对这种批量处理的情形。

  批量插入:

 Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beiginTransaction();
//循环100000次插入100000
for(int i=0; i<100000; i++){
User u = new User();
session.save(u);
}
tx.commit();
session.close();

  但随着这个程序的运行,总会在某个时候运行失败,并且抛出OutOfMemoryException(内存溢出异常)。这是因为Hibernate的Session持有一个必选的一级缓存,所有的User实例都将在Session级别的缓存区进行缓存的缘故。

  为了解决这个问题,有个非常简单的思路:定时将Session缓存的数据刷入数据库,而不是一直在Session级别缓存。可以考虑设计一个累加器,每保存一个User实例,累加器增加1.根据累加器的值决定是否需要将Session缓存的数据刷入数据库。

  下面是增加100000个User实例的代码:

 //打开Session
Session session = HibernateSessionFactory.getSession();
//开始事务
Transaction tx = session.beginTransaction();
//循环100000次,插入100000条记录
for(int i = 0; i < 100000; i++){
User u = new User();
u.setName("XXX");
....
//在session级别缓存Usr实例
session.save(u);
//每当累加器是20的倍数时,将Session中数据刷入数据库
if(i % 20 == 0){
session.fluah();
session.clear();
}
}
//提交事务
tx.commit();
//关闭事务
session.close();

  上面的代码中 i % 20 == 0时,手动将Session处缓存的数据写入数据库,并且清空Session缓存里的数据。除了要对Session级别缓存进行处理外,换应该通过如下配置来关闭SessionFactory的二级缓存。

 hibernate.cache.use_second_level_cache false

除了手动清空Session级别的缓存外,最好关闭SessionFactory级别的二级缓存。否则,即使手动flush Session级别的缓存,但因为在SessionFactory还有二级缓存,也可能引发异常。

  

  批量更新

  上面的方法同样适用于批量更新数据,如果需要换回多行数据,应该使用scroll()方法,从未可以充分利用服务器游标带来的性能优势。下面是进行批量更新的代码片段。

         // 打开Session
Session session = HibernateSessionFactory.getSession();
// 开始事务
Transaction tx = session.beginTransaction();
// 查询User表中的所有记录
ScrollableResults users = session.createQuery("from User")
.setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
//遍历User表中所有的记录
while(users.next()){
User = (User)users.get(0);
u.setName("新用户名"+count);
//当count为20的倍数时
//将更新的结果从Session中flush到数据库
if(++count % 20 == 0){
session.flush();
session.clear();
}
}
tx.commit();
session.close();

  通过这种方式,虽然可以执行批量更新,但效果非常不好。执行效率不高,需要先执行数据查询,然后在执行数据更新,而且这种更新将是逐行更新,即没更新一行记录,都需要执行一条update语句,性能也非常低下。

  为了避免这种情况,Hibernate提供了一种类似于DML语句的批量更新,批量删除的HQL语法。

  

  DML 风格的批量更新/删除

  Hibernate提供的HQL也支持批量的UPDATE和DELETE语法

  批量 UPDATE 和 DELETE语句的语法格式如下:

 UPDATE | DELETE FROM? <ClassName> [WHERE WHERE_CONDITIONS]

  关于上面的语法格式有如下4点值得注意:

  》在FROM字句中,FROM关键字是可选的,即完全可以不写FROM关键字。

  》在FROM字句中只能有一个类名,该类名不能有别名。

  》不能在批量HQL语句中使用连接,显示或者隐式都不可以。但可以在WHERE字句中使用子查询。

  》整个WHERE字句是可选的。WHERE字句的语法和HQL语句中WHERE字句的语法完全相同。

  假设对于上面需要批量更改User类实例的name属性,可以采用如下代码片段完成。

         // 打开Session
Session session = HibernateSessionFactory.getSession();
// 开始事务
Transaction tx = session.beginTransaction();
//定义批量更新的HQL语句
String hqlUpdate = "update User set name = :newName";
//执行更新
int rows = session.createQuery(hqlUpdate).setString("newName", "新名字").executeUpdate();
tx.commit();
session.close();

  从上面的代码中可以看出,这种语法非常类似于PreparedStatement中的executeUpdate()语法,实际上,HQL的这种批量更新就是直接借鉴了SQL语法的UPDATE语句。

  使用这种批量更新语法时,通常只需要执行一次SQL的UPDATE语句,就可以完成所有满足条件记录的更新。但有可能需要执行多条UPDATE语句,这是因为有继承映射等特殊情况,例如有一个Person实例,他有Customer子类实例。当批量更新Person实例时,也需要更新Customer实例。如果采用 joined-subclass或union-subclass映射策略时,Person和Customer实例保存在不同的表中,因此可能需要多条UPDATE语句。

  执行HQL DELETE ,同样适用Query.executeUpdate()方法,下面是一次删除上面全部记录的代码片段。

  1         // 打开Session
2 Session session = HibernateSessionFactory.getSession();
3 // 开始事务
4 Transaction tx = session.beginTransaction();
5 //定义批量删除的HQL语句
6 String hqlDelete = "delete User";
7 //执行删除
8 int rows = session.createQuery(hqlDelete).executeUpdate();
9 tx.commit();
10 session.close();

  Query.executeUpdate()方法返回一个整数值,改值时受此操作影响的记录数量。我们知道 Hibernate的底层操作实际上都是由JDBC完成的,因此,如果有批量的UPDATE或DELETE操作将被转换成多条UPDATE或DELETE语句,该方法只能返回最后一条SQL语句影响的记录行数。

  

Hibernate的批量处理的更多相关文章

  1. hibernate的批量删除

    转自:hibernate的批量删除一般而言,hibernate的批量删除的写法有两种,一种是hibernate内置的批量删除,不过他的批量删除是将每条记录逐一生成删除语句,其效率极低,当然我们可以使用 ...

  2. Hibernate的批量抓取

    批量抓取理解:如果我们需要查找到客户的所有联系人的话,按照正常的思路,一般是首先查询所有的客户,得到返回的客户的List集合.然后遍历List集合,得到集合中的每一个客户,在取出客户中的联系人(客户表 ...

  3. Hibernate的批量插入(&&JDBC)

    来自: http://blog.csdn.net/an_2016/article/details/51759890 一.批量插入(两种方式) 1,通过hibernate缓存 如果这样写代码进行批量插入 ...

  4. Hibernate四 批量处理

    Hibernate批量处理一 批量插入将很多条记录插入数据库时,Hibernate通常会采用以下做法:public void test() { for(int i=0;i<1000;i++){ ...

  5. Hibernate、批量操作数据

    Hibernate 批量操作数据可以使用两种方法实现 1.分批更新,每一小批同步一次数据: public void saveEmployee2(){ Session s=HibernateSessio ...

  6. 使用JPA和Hibernate进行批量处理的最佳方式

    Tips 原文作者:Vlad Mihalcea 原文地址:The best way to do batch processing with JPA and Hibernate 在本文中,你将了解什么是 ...

  7. Hibernate的批量处理和分页技术、投影技术

    投影查询——过滤部分字段返回的List集合元素为Object[] Query query = session.createQuery("select c.cname, c.csex from ...

  8. Hibernate 中批量处理数据

    一.批量处理操作 批量处理数据是指在一个事务场景中处理大量数据.在应用程序中难以避免进行批量操作,Hibernate提供了以下方式进行批量处理数据: (1)使用HQL进行批量操作     数据库层面 ...

  9. Hibernate的批量查询

    Hibernate的查询大致分为以下三种场景, 1. HQL查询-hibernate Query Language(多表查询,但不复杂时使用)    2. Criteria查询(单表条件查询) 3. ...

随机推荐

  1. 纠结的CLI C++与Native C++的交互

    最近在写点东西,涉及到了CLR C++与Native C++的互相调用的问题,结果...........纠结啊. 交互原型 交互原型是这样的: void* avio_alloc_context( un ...

  2. 从一个简单的Java单例示例谈谈并发 JMM JUC

    原文: http://www.open-open.com/lib/view/open1462871898428.html 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这 ...

  3. STRUCTS 2 LABLE

    {LJ?Dragon}[标题]structs2标签的作用 {LJ?Dragon}[Diary]2017年,愉快的开始:离别不一定总伤感,虽然只是安慰着自己......... 问与答 问题 在Strut ...

  4. Excel导入数据库(三)——SqlBulkCopy

    上篇博客中介绍了批量导入数据库的方法:下面介绍一下批量导入过程的核心——SqlBulkCopy类. 下面先介绍一些原理性的东西:SQLBulkCopy类,通常用于数据库之间大批量的数据传递.即使表结构 ...

  5. IOS中UITableViewCell的重用机制原理

    创建UITableViewController子类的实例后,IDE生成的代码中有如下段落: - (UITableViewCell *)tableView:(UITableView *)tableVie ...

  6. webservice使用基本技巧

    一,webService基本概念 webService也叫XMLWeb SerVice WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独 ...

  7. android 时间对话框 TimePickerDialog简介

     个人也提醒功能的时候用到了TimePickerDialog对话框,查阅了非常多技术资料,可是感觉非常多东西都说的不是非常具体,而且非常多地方.都有不完好的地方.比方有弹出对话框得到的不是系统当前 ...

  8. Linux 内核的文件 Cache 管理机制介绍-ibm

    https://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使 ...

  9. 从零开始学习jQuery-------jQuery元素选择器(三)

    下面我们来介绍一下jQuery元素选择器,在Web开发中我们最常用的操作是获取元素,然后对获取的元素进行一系列的操作,jQuery根据获取页面元素的不同,可以将jQuery选择器分为四大类:基本选择器 ...

  10. AS 进行单元测试

    以下为本人在AndroidStudio 2.0 上实测后得出的结论,不像网上那一堆堆的误人子弟的文章,都是过时的或者根本就是不对的. 简介 和eclipse需要配置清单文件不同,AndroidStud ...