- 浏览: 895279 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (687)
- java (127)
- servlet (38)
- struts (16)
- spring (22)
- hibernate (40)
- javascript (58)
- jquery (18)
- tomcat (51)
- 设计模式 (6)
- EJB (13)
- jsp (3)
- oracle (29)
- RUP (2)
- ajax (3)
- java内存管理 (4)
- java线程 (12)
- socket (13)
- path (5)
- XML (10)
- swing (2)
- UML (1)
- JBPM (2)
- 开发笔记 (45)
- Note参考 (15)
- JAXB (4)
- Quartz (2)
- 乱码 (2)
- CSS (2)
- Exception (4)
- Tools (7)
- sqlserver (3)
- DWR (7)
- Struts2 (47)
- WebService (2)
- 问题解决收藏 (7)
- JBOSS (7)
- cache (10)
- easyUI (19)
- jQuery Plugin (11)
- FreeMarker (6)
- Eclipse (2)
- Compass (2)
- JPA (1)
- WebLogic (1)
- powerdesigner (1)
- mybatis (1)
最新评论
-
bugyun:
受教了,谢谢
java 正则表达式 过滤html标签 -
xiongxingxing_123:
学习了,感谢了
java 正则表达式 过滤html标签 -
wanmeinange:
那如果无状态的。对同一个任务并发控制怎么做?比如继承Quart ...
quartz中参数misfireThreshold的详解 -
fanjieshanghai:
...
XPath 元素及属性查找 -
tianhandigeng:
还是没明白
quartz中参数misfireThreshold的详解
【IT168 技术文档】
摘要:很久以来,Hibernate的批处理操作的性能受一部分使用群体的质疑,他们可能还是觉得JDBC的在这方面的处理能力要强得多。我们大家都知道Hibernate是对JDBC进行轻量级别的封装,Hibernate的操作最终要回归到JDBC操作的执行。本文重点探讨Hibernate的批处理操作在性能上的影响,分三种情况来说明,分别是批量插入,批量更新,批量删除。
一:批量插入
在项目的开发过程之中,由于项目需求,我们常常需要把大批量的数据插入到数据库。数量级有万级、十万级、百万级、甚至千万级别的。如此数量级别的数据用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参数,可参考如下配置。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><hibernate-configuration>
<session-factory>
.........
<property name=” hibernate.jdbc.batch_size”>50</property>
.........
<session-factory>
<hibernate-configuration>
![]()
配置hibernate.jdbc.batch_size参数的原因就是尽量少读数据库,hibernate.jdbc.batch_size参数值越大,读数据库的次数越少,速度越快。从上面的配置可以看出,Hibernate是等到程序积累到了50个SQL之后再批量提交。
笔者也在想,hibernate.jdbc.batch_size参数值也可能不是设置得越大越好,从性能角度上讲还有待商榷。这要考虑实际情况,酌情设置,一般情形设置30、50就可以满足需求了。
程序实现方面,笔者以插入10000条数据为例子,如:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->Session session=HibernateUtil.currentSession();
Transatcion tx=session.beginTransaction();
for(int i=0;i<10000;i++)
...{
Student st=new Student();
st.setName(“feifei”);
session.save(st);
if(i%50==0) //以每50个数据作为一个处理单元
...{
session.flush(); //保持与数据库数据的同步
session.clear(); //清除内部缓存的全部数据,及时释放出占用的内存
}
}
tx.commit();
.........
![]()
在一定的数据规模下,这种做法可以把系统内存资源维持在一个相对稳定的范围。
注意:前面提到二级缓存,笔者在这里有必要再提一下。如果启用了二级缓存,从机制上讲Hibernate为了维护二级缓存,我们在做插入、更新、删除操作时,Hibernate都会往二级缓存充入相应的数据。性能上就会有很大损失,所以笔者建议在批处理情况下禁用二级缓存。
对于方法2,采用传统的JDBC的批处理,使用JDBC API来处理。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->.......
Connection conn=DB.getConnection();
PreparedStatement stmt=conn.prepareStatement(“insert into T_STUDENT(name) values(?) ”);
for(int j=0;j<200;j++)...{
for(int i=0;i<50;i++)...{
stmt.setString(1,”feifei”);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
}
.......
![]()
看看上面的代码,是不是总觉得有不妥的地方?对,没发现么!这还是JDBC的传统编程,没有一点Hibernate味道。
可以对以上的代码修改成下面这样:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->Transaction tx=session.beginTransaction(); //使用Hibernate事务处理 边界Connection conn=session.connection();
PrepareStatement stmt=conn.prepareStatement(“insert into T_STUDENT(name) values(?)”);
for(int j=0;j++;j<200)...{
for(int i=0;i++;j<50)
...{
stmt.setString(1,”feifei”);
}
}
stmt.executeUpdate();
tx.commit(); //使用 Hibernate事务处理边界
.........
![]()
这样改动就很有Hibernate的味道了。笔者经过测试,采用JDBC API来做批量处理,性能上比使用Hibernate API要高将近10倍,性能上JDBC 占优这是无疑的。
二:批量更新与删除
Hibernate2中,对于批量更新操作,Hibernate是将符合要求的数据查出来,然后再做更新操作。批量删除也是这样,先把符合条件的数据查出来,然后再做删除操作。
这样有两个大缺点:
(1):占用大量的内存。
(2):处理海量数据的时候,执行update/delete语句就是海量了,而且一条update/delete语句只能操作一个对象,这样频繁的操作数据库,性能低下应该是可想而知的了。
Hibernate3 发布后,对批量更新/删除操作引入了bulk update/delete,其原理就是通过一条HQL语句完成批量更新/删除操作,很类似JDBC的批量更新/删除操作。在性能上,比Hibernate2的批量更新/删除有很大的提升。
下面给出参考代码:把T_STUDENT表中数据都删除。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->Transaction tx=session.beginSession();
String HQL=”delete STUDENT”;
Query query=session.createQuery(HQL);
int size=query.executeUpdate();
tx.commit();
.......
![]()
控制台输出了也就一条删除语句Hibernate:delete from T_STUDENT,语句执行少了,性能上也与使用JDBC相差无几,是一个提升性能很好的方法。当然为了有更好的性能,笔者建议批量更新与删除操作还是使用JDBC,方法以及基本的知识点与上面的批量插入方法2基本相同,这里就不在冗述。
笔者这里再提供一个方法,就是从数据库端来考虑提升性能,在Hibernate程序端调用存储过程。存储过程在数据库端运行,速度更快。以批量更新为例,给出参考代码。
首先在数据库端建立名为batchUpdateStudent存储过程:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->create or replace produre batchUpdateStudent(a in number) as
begin
update STUDENT set AGE=AGE+1 where AGE>a;
end;
调用代码如下:
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的事务边界。存储过程无疑是提高批量处理性能的一个好方法,直接运行与数据库端,某种程度上讲把批处理的压力转接给了数据库。
三:编后语
本文探讨了Hibernate的批处理操作,出发点都是在提高性能上考虑了,也只是提供了提升性能的一个小方面。
不管采取什么样的方法,来提升性能都要根据实际的情况来考虑,为用户提供一个满足需求的而且高效稳定的系统才是重中之中。
发表评论
文章已被作者锁定,不允许评论。
-
Criteria查询,DetachedCriteria离线查询 --做综合查询
2011-09-06 00:25 1611通过Session得到Criteria类的对象 Ja ... -
Hibernate批量操作(JDBC批量操作)
2011-09-06 00:24 1303部分内容转自 :http://ga ... -
Hibernate懒加载深入分析
2011-09-06 00:19 1340懒加载可以提高性能吗? 不可以简单的说"能" ... -
getSesson currentSession
2011-09-06 00:15 10181 getCurrentSession创建的session会和 ... -
Hibernate 操作Blob Clob
2011-09-05 23:46 1080Photo.java Java代码 i ... -
Hibernate建表错误,Could not determine type for: java.util.List
2011-04-04 22:19 1668今天遇到 Could not determine type f ... -
Hibernate的fetch="join"和fetch="select"
2011-03-24 14:16 980fetch参数指定了关联对 ... -
Hibernate的Criteria用法总结
2011-03-23 10:53 786最近在项目中使用 Struts 和 Hibernate 进行开 ... -
第29讲--为Spring集成的Hibernate配置二级缓存
2011-03-10 23:16 1109合理的使用缓存策略,往往在web开发中提高性能起到关键作用。 ... -
hibernate抓取策略
2011-02-12 13:23 828Hibernate最让人头大的就是对集合的加载形式。书看了N次 ... -
Hibernate笔记:HQL查询总结(一)——简单属性查询和实体对象查询
2011-02-01 23:38 3505本文一部分转自kuangbaoxu的博文hibernate-- ... -
Hibernate笔记:HQL查询总结(二)——条件查询
2011-02-01 23:35 1518条件查询 1.拼字符串 where条件后面,可以用字 ... -
Hibernate属性延迟加载
2011-02-01 21:28 1023Hibernate3开始增加了通过property节点的la ... -
Hibernate中的cascade和inverse
2011-01-31 00:31 1004这两个属性都用于一多对或者多对多的关系中。而inverse特别 ... -
batch_size 和 fetch_size作用
2010-12-01 21:37 1290hibernate抓取策略,,batch-szie在< ... -
hibernate中SQLQuery的addEntity();方法
2010-10-20 10:48 2789如果使用原生sql语句进行query查询时,hibernate ... -
Hibernate的evict方法错误总结
2010-10-14 10:08 1226摘自百度知道:http://zhi ... -
hibernate中get方法和load方法的区别
2010-10-14 09:57 809键字: hibernate get load 区 ... -
Hibernate: 设A引用了B,则删A后可能要evict(A.getB())
2010-10-14 09:56 1017Hibernate: 设A引用了B,如果要先取A删A再取B删B ... -
Hibernate的flush()和evict()总结
2010-10-14 09:53 1338关键字: hibernate flush() evict() ...
相关推荐
本篇文章将详细探讨如何利用JSF与Hibernate相结合来实现批量删除功能,以及在CRUD(创建、读取、更新和删除)操作中的应用。 首先,我们需要理解JSF的工作原理。JSF是一个基于组件的MVC(Model-View-Controller)...
本篇文章将针对“hibernate-3.0.zip”这一版本进行详细讲解,带你深入理解Hibernate 3.0的核心机制,以及如何在实际项目中有效地运用它。 一、Hibernate 3.0概述 Hibernate 3.0是Hibernate系列的一个重要版本,它在...
在本篇文章中,我们将深入探讨Hibernate 3.2.5中的核心概念、特性以及它如何简化Java数据库编程。 1. **对象关系映射(ORM)**:Hibernate作为ORM工具,将Java对象与数据库表进行映射,使得开发者可以处理Java对象...
作为“从入门到精通”系列的第二篇,本教程将建立在第一篇的基础之上,进一步扩展对Hibernate的理解。 【描述】:“最经典的hibernate教程_从入门到精通_第二篇” 本教程旨在提供一个全面的Hibernate学习路径,让...
在SSH(Spring、Struts、Hibernate)架构中,Hibernate是处理数据库交互的核心组件。本篇文章将汇总Hibernate 3配置文件中的关键参数,帮助开发者更好地理解和配置Hibernate。 1. **SQL方言(Dialect)**:`hibernate...
本篇文章将探讨如何对Hibernate的`Session`进行简单的包装,以提升代码的可维护性和灵活性。`Session`是Hibernate的核心组件,它负责对象的持久化操作,如保存、更新、查询等。 `Session`接口提供了多种方法来与...
在本篇中,我们将深入探讨Hibernate API的核心概念、功能以及使用方法。 ### 1. Hibernate核心组件 - **SessionFactory**: SessionFactory是Hibernate的核心,它是线程安全的,负责初始化配置并创建Session实例。...
本篇文章将详细探讨如何使用Java来实现Oracle数据库的批量入库操作。 首先,我们需要了解Oracle数据库的基本操作。在Java中,我们通常通过JDBC(Java Database Connectivity)接口来连接并操作数据库。JDBC提供了一...
Spring框架是中国Java开发领域中不可或缺的核心技术之一,它以其强大的功能和灵活性,为开发者提供了构建企业级应用的高效平台。SSH(Struts、Spring、Hibernate)是经典的Java Web开发三大框架,而Spring作为其中的...
9. **Spring Batch**:用于处理批量处理任务,提供了易用的API和强大的功能,如跳过失败项、交易支持等。 压缩包中的`Spring2cnFinal.chm`文件很可能是一个包含Spring中文文档的离线帮助文件,通常这样的文件包含了...
在本篇文章中,我们将深入探讨Spring框架的各个方面,包括其设计理念、主要模块、核心功能以及如何在实际项目中应用。 1. **依赖注入(Dependency Injection,DI)** 依赖注入是Spring框架的核心,它允许我们解耦...
这篇“Spring开发指南”深入探讨了Spring的核心概念和实际应用,旨在帮助开发者更好地理解和使用这一框架。 一、Spring框架概述 Spring是一个开源的Java应用框架,它简化了Java企业级应用的开发,通过提供一套全面...
9. **Spring Batch**:用于处理批量数据操作,支持重试、跳过、分割和并行处理等特性。 10. **Spring Integration**:提供企业服务总线(ESB)功能,方便系统间的集成和通信。 以上知识点涵盖了Spring框架的多个...
Spring是Java开发中最流行的轻量级框架之一,它提供了丰富的功能,包括依赖注入、AOP(面向切面编程)、数据访问、事务管理、Web应用以及更多。了解Spring的基本概念和深入原理对于Java开发者来说至关重要。 描述中...
`JdbcTemplate`是Spring对JDBC API的一个轻量级包装,它通过提供一系列模板方法来处理常见的JDBC操作,如查询、更新、插入和删除数据。这样可以避免手动处理连接、事务和异常,降低了代码的复杂性。`JdbcTemplate`...
在本篇中,我们将深入探讨这一主题,主要关注其在Java环境下的应用。 首先,让我们了解一下什么是代码自动生成。代码自动生成是指通过自动化工具,依据预先定义好的规则或模式,批量生成符合特定需求的源代码。这...
##### jdbc分段批量提交的时候出现异常怎么处理? - 使用try-catch块捕获异常。 - 在catch块内回滚事务。 - 可以使用日志记录错误详情。 ##### jdbc批量处理数据 - 使用PreparedStatement对象的addBatch()方法添加...
### Spring-data-jpa 学习笔记 ...综上所述,Spring Data JPA 是一个强大的工具,它不仅简化了 JPA 的使用,还提供了一系列的高级功能,使得开发者能够在保持代码简洁的同时,实现更为复杂的数据操作需求。