`

Hibernate应用系列之六批量处理篇

阅读更多

【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的批处理操作,出发点都是在提高性能上考虑了,也只是提供了提升性能的一个小方面。
    不管采取什么样的方法,来提升性能都要根据实际的情况来考虑,为用户提供一个满足需求的而且高效稳定的系统才是重中之中。

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    JSF+hibernate实现批量删除

    本篇文章将详细探讨如何利用JSF与Hibernate相结合来实现批量删除功能,以及在CRUD(创建、读取、更新和删除)操作中的应用。 首先,我们需要理解JSF的工作原理。JSF是一个基于组件的MVC(Model-View-Controller)...

    hibernate-3.0.zip

    本篇文章将针对“hibernate-3.0.zip”这一版本进行详细讲解,带你深入理解Hibernate 3.0的核心机制,以及如何在实际项目中有效地运用它。 一、Hibernate 3.0概述 Hibernate 3.0是Hibernate系列的一个重要版本,它在...

    hibernate 3,25

    在本篇文章中,我们将深入探讨Hibernate 3.2.5中的核心概念、特性以及它如何简化Java数据库编程。 1. **对象关系映射(ORM)**:Hibernate作为ORM工具,将Java对象与数据库表进行映射,使得开发者可以处理Java对象...

    最经典的hibernate教程_从入门到精通_第二篇

    作为“从入门到精通”系列的第二篇,本教程将建立在第一篇的基础之上,进一步扩展对Hibernate的理解。 【描述】:“最经典的hibernate教程_从入门到精通_第二篇” 本教程旨在提供一个全面的Hibernate学习路径,让...

    hibernate_3配置文件参数汇总

    在SSH(Spring、Struts、Hibernate)架构中,Hibernate是处理数据库交互的核心组件。本篇文章将汇总Hibernate 3配置文件中的关键参数,帮助开发者更好地理解和配置Hibernate。 1. **SQL方言(Dialect)**:`hibernate...

    对Hibernate Session做一个简单的包装

    本篇文章将探讨如何对Hibernate的`Session`进行简单的包装,以提升代码的可维护性和灵活性。`Session`是Hibernate的核心组件,它负责对象的持久化操作,如保存、更新、查询等。 `Session`接口提供了多种方法来与...

    Hibernate_api

    在本篇中,我们将深入探讨Hibernate API的核心概念、功能以及使用方法。 ### 1. Hibernate核心组件 - **SessionFactory**: SessionFactory是Hibernate的核心,它是线程安全的,负责初始化配置并创建Session实例。...

    java操作Oracle批量入库

    本篇文章将详细探讨如何使用Java来实现Oracle数据库的批量入库操作。 首先,我们需要了解Oracle数据库的基本操作。在Java中,我们通常通过JDBC(Java Database Connectivity)接口来连接并操作数据库。JDBC提供了一...

    spring-framework

    Spring框架是中国Java开发领域中不可或缺的核心技术之一,它以其强大的功能和灵活性,为开发者提供了构建企业级应用的高效平台。SSH(Struts、Spring、Hibernate)是经典的Java Web开发三大框架,而Spring作为其中的...

    Spring Framework 开发参考手册

    9. **Spring Batch**:用于处理批量处理任务,提供了易用的API和强大的功能,如跳过失败项、交易支持等。 压缩包中的`Spring2cnFinal.chm`文件很可能是一个包含Spring中文文档的离线帮助文件,通常这样的文件包含了...

    spring精华spring精华

    在本篇文章中,我们将深入探讨Spring框架的各个方面,包括其设计理念、主要模块、核心功能以及如何在实际项目中应用。 1. **依赖注入(Dependency Injection,DI)** 依赖注入是Spring框架的核心,它允许我们解耦...

    Spirng开发指南

    这篇“Spring开发指南”深入探讨了Spring的核心概念和实际应用,旨在帮助开发者更好地理解和使用这一框架。 一、Spring框架概述 Spring是一个开源的Java应用框架,它简化了Java企业级应用的开发,通过提供一套全面...

    spring培训的例子

    9. **Spring Batch**:用于处理批量数据操作,支持重试、跳过、分割和并行处理等特性。 10. **Spring Integration**:提供企业服务总线(ESB)功能,方便系统间的集成和通信。 以上知识点涵盖了Spring框架的多个...

    spring面试题.rar

    Spring是Java开发中最流行的轻量级框架之一,它提供了丰富的功能,包括依赖注入、AOP(面向切面编程)、数据访问、事务管理、Web应用以及更多。了解Spring的基本概念和深入原理对于Java开发者来说至关重要。 描述中...

    _Spring_使用 JdbcTemplate和JdbcDaoSupport.rar

    `JdbcTemplate`是Spring对JDBC API的一个轻量级包装,它通过提供一系列模板方法来处理常见的JDBC操作,如查询、更新、插入和删除数据。这样可以避免手动处理连接、事务和异常,降低了代码的复杂性。`JdbcTemplate`...

    代码自动生成工具包

    在本篇中,我们将深入探讨这一主题,主要关注其在Java环境下的应用。 首先,让我们了解一下什么是代码自动生成。代码自动生成是指通过自动化工具,依据预先定义好的规则或模式,批量生成符合特定需求的源代码。这...

    java面试知识

    ##### jdbc分段批量提交的时候出现异常怎么处理? - 使用try-catch块捕获异常。 - 在catch块内回滚事务。 - 可以使用日志记录错误详情。 ##### jdbc批量处理数据 - 使用PreparedStatement对象的addBatch()方法添加...

    Spring-data-jpa 学习笔记.docx

    ### Spring-data-jpa 学习笔记 ...综上所述,Spring Data JPA 是一个强大的工具,它不仅简化了 JPA 的使用,还提供了一系列的高级功能,使得开发者能够在保持代码简洁的同时,实现更为复杂的数据操作需求。

Global site tag (gtag.js) - Google Analytics