`

09-Hibernate3.6.2 批量处理

阅读更多

 

前面我们总结了Hibernate的查询操作,今天我们来说说Hibernate的批量处理。

         Hibernate完全以面向对象的方式操作数据库,当程序里以面向对象的方式操作持久化对象时,将被自动转换为对数据库的操作,例如调用Sessiondelete()方法来删除持久化对象,Hibernate将负责删除对应的数据记录;当执行持久化对象的set方法时,Hibernate将自动转换为对应的update方法,修改数据库的对应记录。问题是如果需要同时更新100 000条记录,是不是要逐一加载100 000条记录,然后依次调用set方法——这样不仅繁琐,数据访问的性能也十分糟糕。对这种批量处理的场景,Hibernate提供了批量处理的解决方案,

         所谓的批量处理数据是指在一个事务中处理大量数据。

一般来说,应该尽可能避免在应用层进行批量操作,而应该在数据库层直接进行批量操作。例如直接在数据库中执行用于批量更新或删除的SQL语句,如果批量操作的逻辑比较复杂,则可以通过直接在数据库中运行的存储过程来完成批量操作。并不是所有的数据库系统都支持存储过程。例如目前的MySQL就不支持存储过程,因此不能通过存储过程来进行批量更新或批量删除。当然,在应用层也可以进行批量操作,主要有以下方式:

1)通过Session来进行批量操作。

  2)通过StatelessSession来进行批量操作。

  3)通过HQL来进行批量操作。

  4)直接通过JDBC API来进行批量操作。

 

一、通过Session进行批量操作

Sessionsave()方法以及update()方法都会把处理的对象存放在自己的缓存中。如果通过一个Session对象来处理大量持久化对象,应该及时从缓存中清空已经处理完并且不会在访问的对象,具体的做法是在处理完一个对象或小批量对象后,立刻调用flush()方法清理缓存,然后再调用clear()方法清空缓存。

通过Session来进行批量处理会受到以下约束:

1)需要在Hibernate的配置文件中设置JDBC单次批量处理的数目,合理的取值通常为1050之间,例如:

<hibernate-configuration>
    <session-factory>
        .........
        <property name="hibernate.jdbc.batch_size">50</property>
        .........
    <session-factory>
<hibernate-configuration>

    (2)如果对象采用"identity"标识符生成器,则Hibernate无法在JDBC层进行批量插入操作。

3)进行批量操作时,建议关闭Hibernate的第二级缓存。Session的缓存为Hibernate的第一级缓存,通常它是事务范围内的缓存,也就是说,每个事务都有单独的第一级缓存。SessionFactory的外置缓存为Hibernate的第二级缓存,它是应用范围内的缓存,也就是说,所有事务都共享同一个第二级缓存。在任何情况下,Hibernate的第一级缓存总是可用的。而默认情况下,Hibernate的第二级缓存是关闭的,此外也可以在Hibernate的配置文件中通过如下方式显式关闭第二级缓存:
hibernate.cache.use_second_level_cache=false

 

1、  批量插入

Session session = sessionFactory.openSession();
	Transaction tx = session.beginTransaction();
	for ( int i=0; i<100000; i++ ) {
		Customer customer = new Customer(.....);
		session.save(customer);
		if ( i % 20 == 0 ) { //单次批量操作的数目为20
			session.flush();//清理缓存,执行批量插入20条记录的SQL insert语句
			session.clear();//清空缓存中的Customer对象
		}
	}
	tx.commit();
	session.close();

在以上程序中,每次执行session.flush()方法,就会向数据库中批量插入20条记录。接下来session.clear()方法把20个刚保存的Customer对象从缓存中清空。

为了保证以上程序顺利运行,需要遵守以下约束。

  1、在Hibernate的配置文件中,应该把hibernate.jdbc.batch_size属性也设为20

  2、关闭第二级缓存。因为假如使用了第二级缓存,那么所有在第一级缓存(即Session的缓存)中创建的Customer对象还要先复制到第二级缓存中,然后再保存到数据库中,这会导致大量不必要的开销。

  3Customer对象的标识符生成器不能为"identity"

 

1、  批量更新

进行批量更新时,如果一下子把所有对象到加载到Session的缓存中,然后再在缓存中一一更新它们,显然是不可取的。为了解决这一问题,可以使用可滚动的结果集org.hibernate.ScrollableResultsQueryscroll()方法返回一个ScrollableResults对象。以下代码演示批量更新Customer对象,该代码一开始利用ScrollableResults对象来加载所有的Customer对象:

Session session = sessionFactory.openSession();
	Transaction tx = session.beginTransaction();
	ScrollableResults customers = session.getNamedQuery("GetCustomers")
		.setCacheMode(CacheMode.IGNORE)
		.scroll(ScrollMode.FORWARD_ONLY);
	int count=0;
	while ( customers.next() ) {
		Customer customer = (Customer) customers.get(0);
		customer.updateStuff(...);//更新Customer对象
		if ( ++count % 20 == 0 ) {//单次批量操作的数目为20
			session.flush();//清理缓存,执行批量更新20条记录的SQL update语句
			session.clear();//清空缓存中的Customer对象
		}
	}
	tx.commit();
	session.close();

在以上代码中,Queryscroll()方法返回的ScrollableResults对象中实际上并不包含任何Customer对象,它仅仅包含了用于在线定位数据库中CUSTOMERS记录的游标。只有当程序遍历访问ScrollableResults对象中的特定元素时,它才会到数据库中加载相应的Customer对象。

为了保证以上程序顺利运行,需要遵守以下约束:

        1、在Hibernate的配置文件中,应该把hibernate.jdbc.batch_size属性也设为20

        2、关闭二级缓存。假如已经在配置文件中启用了二级缓存,也可以通过以下方式在程序中忽略第二级缓存:setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY)

 

二、通过StatelessSession(无状态Session)来进行批量操作

Session具有一个用于保持内存中对象与数据库中相应数据保持同步的缓存,位于Session缓存中的对象为持久化对象。但在进行批量操作时,把大量对象存放在Session缓存中会消耗大量内存空间。作为一种替代方案,可以采用无状态的StatelessSession来进行批量操作。

StatelessSession:

无状态 session 不实现第一级 cache,也不和第二级缓存,或者查询缓存交互。它不实现事务化,也不实现脏数据检查。用 stateless session 进行的操作甚至不级联到关联实例。stateless session 忽略集合类(Collections)。通过 stateless session 进行的操作不触发 Hibernate 的事件模型和拦截器。无状态 session 对数据的混淆现象免疫,因为它没有第一级缓存。无状态 session 是低层的抽象,和低层 JDBC 相当接近。

	StatelessSession session = sessionFactory.openStatelessSession();
	Transaction tx = session.beginTransaction();
	ScrollableResults customers = session.getNamedQuery("GetCustomers").scroll(ScrollMode.FORWARD_ONLY);
	while ( customers.next() ) {
		Customer customer = (Customer) customers.get(0);
		customer.updateStuff(...);
		session.update(customer);
	}
	tx.commit();
	session.close();

 

从形式上看,StatelessSessionSession的用法有点相似。StatelessSessionSession相比,有以下区别:

 1StatelessSession没有缓存,通过StatelessSession来加载、保存或更新后的对象都处于游离状态。

 2StatelessSession不会与Hibernate的第二级缓存交互。

 3)当调用StatelessSessionsave()update()delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅仅计划执行一条SQL语句。

 4StatelessSession不会对所加载的对象自动进行脏检查。所以在以上程序中,修改了内存中Customer对象的属性后,还需要通过StatelessSessionupdate()方法来更新数据库中的相应数据。

 5StatelessSession不会对关联的对象进行任何级联操作。举例来说,通过StatelessSession来保存一个Customer对象时,不会级联保存与之关联的Order对象。

 6StatelessSession所做的操作可以被Interceptor拦截器捕获到,但会被Hibernate的事件处理系统忽略。

 7)通过同一个StatelessSession对象两次加载OID1Customer对象时,会得到两个具有不同内存地址的Customer对象,例如:

StatelessSession session = sessionFactory.openStatelessSession();
Customer c1=(Customer)session.get(Customer.class,new Long(1));
Customer c2=(Customer)session.get(Customer.class,new Long(1));
System.out.println(c1==c2); //打印false

 

三、通过HQL来进行批量操作

 

1、批量更新

Session session = sessionFactory.openSession();
	Transaction tx = session.beginTransaction();
	 
	String hqlUpdate ="update Customer c set c.name = :newName where c.name = :oldName";
	int updatedEntities = session.createQuery( hqlUpdate )
	 	.setString( "newName", "Mike" )
	 	.setString( "oldName", "Tom" )
	 	.executeUpdate();
	 
	tx.commit();
	session.close();

 

2、批量删除

	 Session session = sessionFactory.openSession();
	 Transaction tx = session.beginTransaction();
	 
	 String hqlDelete = "delete Customer c where c.name = :oldName";
	 int deletedEntities = session.createQuery( hqlDelete )
	 	.setString( "oldName", "Tom" )
	 	.executeUpdate();
	 tx.commit();
	 session.close();

 

四、直接通过JDBC API来进行批量操作

 

 

分享到:
评论

相关推荐

    mongodb-cxx-driver-r3.6.2使用vs2017编译的项目和测试代码

    这个驱动程序基于`mongo-c-driver`,并提供了一层更高级别的抽象,使得C++开发人员能更容易地处理文档和集合。解压后,`mongo-cxx-driver-r3.6.2`目录下有头文件、源文件和示例代码,可以帮助理解和使用驱动程序。 ...

    apache-zookeeper-3.6.2-bin.tar

    apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-...

    apache-maven-3.6.2-bin.tar.gz

    总之,`apache-maven-3.6.2-bin.tar.gz`提供了Java项目管理和构建的强大工具,通过解压、配置环境变量以及编写和管理POM,开发者能够高效地处理复杂的项目依赖和构建流程。Maven 3.6.2版本修复了一些已知问题,提高...

    rocketmq-client-3.6.2.Final-API文档-中文版.zip

    赠送jar包:rocketmq-client-3.6.2.Final.jar; 赠送原API文档:rocketmq-client-3.6.2.Final-javadoc.jar; 赠送源代码:rocketmq-client-3.6.2.Final-sources.jar; 包含翻译后的API文档:rocketmq-client-...

    hibernate-distribution-3.6.2 API及jar包

    《Hibernate 3.6.2 API及jar包详解》 Hibernate,作为一个强大的对象关系映射(ORM)框架,是Java开发中的重要工具。...通过深入学习和实践,你将能够熟练掌握Hibernate,提升Java应用程序的数据处理能力。

    hibernate-distribution-3.6.2.Final-dist

    1. `hibernate-core`: Hibernate的核心组件,包含对象/关系映射、查询、事务处理等功能。 2. `hibernate-entitymanager`: 实现JPA规范的模块,提供了对JPA的支持。 3. `hibernate-tools`: 提供了Hibernate相关的辅助...

    apache-maven-3.6.2-bin.zip

    `apache-maven-3.6.2-bin.zip` 是Apache Maven的3.6.2版本的二进制发行版,它不包含源码或其他分支,因此是针对那些只需要执行构建任务而不涉及开发或调试的用户。 Maven的核心概念是项目对象模型(Project Object ...

    BaiduPCS-Go-v3.6.2-linux-amd64.zip

    v3.6.2 更新日志: 1.修复文件md5显示错误 2.修复无法上传 3.修复分享列表获取不到密码 4.更新上传、下载处理流程,优化重试的判断条件 5.更新download命令, 移除之前的-stream -share -locate等参数,新增-mode参数,...

    rocketmq-client-3.6.2.Final-API文档-中英对照版.zip

    赠送jar包:rocketmq-client-3.6.2.Final.jar; 赠送原API文档:rocketmq-client-3.6.2.Final-javadoc.jar; 赠送源代码:rocketmq-client-3.6.2.Final-sources.jar; 包含翻译后的API文档:rocketmq-client-...

    apache-maven-3.6.2_maven_

    它使用一种称为传递性依赖的概念,意味着如果项目A依赖于项目B,而项目B又依赖于项目C,那么Maven会自动处理项目A对项目C的依赖,无需在项目A的POM中显式声明。 对于初学者来说,Maven简化了项目结构,通常遵循标准...

    apache-maven-3.6.2-bin安装包.rar

    在这个“apache-maven-3.6.2-bin”安装包中,包含了运行Maven所需的所有核心组件、插件和文档。 1. **Maven的基本概念**: Maven是基于项目对象模型(Project Object Model, POM)的概念,通过XML文件定义项目的...

    ksoap2-android-assembly-3.6.2-jar-with-dependencies

    总的来说,ksoap2-android-assembly-3.6.2-jar-with-dependencies是Android开发者与远程Web服务交互的强大工具,它的易用性和全面的功能使得处理复杂的SOAP通信变得更加简单。通过熟练掌握这个库的使用,开发者可以...

    kafka安装包-2.13-3.6.2

    总之,`kafka_2.13-3.6.2`是Apache Kafka的一个版本,适用于Scala 2.13环境,提供了一整套消息处理能力,是构建现代大数据实时处理系统的重要组件。正确安装和配置Kafka,可以充分利用其高性能和高可用性特性,为...

    apache-maven-3.6.2.zip

    "apache-maven-3.6.2.zip" 是Apache Maven 3.6.2版本的压缩包,包含了所有必要的组件和文件,便于用户在本地环境中安装和使用。 在提供的压缩包文件列表中,我们可以看到以下几个关键文件和目录: 1. **LICENSE**...

    ksoap2-android3.6.2

    kSOAP2-android 3.6.2是这个库的一个特定版本,它包含了对Android平台的优化和适配。这个版本可能包含了一些新特性、性能改进或者错误修复,以提供更好的稳定性和兼容性。更新到这个版本,开发者可以确保他们的应用...

    eclipse-sourceBuild-srcIncluded-3.6.2

    eclipse-sourceBuild-srcIncluded-3.6.2

    lucene-core-3.6.2.jar

    3.6.2版本是lucene的3x中最大的版本,也是3x中最稳定的版本,因此建设使用该版本。如果还是使用3.6.0或3.6.1,更要升级到该版本...想下载源码包的,可以搜索源码包lucene-core-3.6.2-src.jar及lucene-queries-3.6.2.jar

    apache-solr-3.6.2.zip

    apache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zip

    eclipse-SDK-3.6.2-win32.part3

    eclipse-SDK-3.6.2-win32.part3

Global site tag (gtag.js) - Google Analytics