首页 > 其他分享 >Hibernate4性能之批量处理的三种方式

Hibernate4性能之批量处理的三种方式

时间:2023-03-21 11:31:59浏览次数:28  
标签:Hibernate4 Customer 缓存 批量 tx ... customer session 三种


[url]http://zhou137520.iteye.com/blog/1611621[/url]

假如有如下程序,需要向数据库里面加如100000条数据

Session session = sessionFactory.openSession();    
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
}
tx.commit();
session.close();




这段程序大概运行到50000条记录左右会失败并抛出内存溢出异常(OutOfMemoryException),按照前面讲过的原理,新产生的object瞬时对象变为持久对象后,在session关闭之前将自动装载到session级别的缓存区,如果,程序使用了二级缓存,同样也会装入到二级缓存。所以当数据量大时,导致内存溢出。



解决方案:


设置批量抓取数量参数设置到一个合适值(比如10-50之间),同时最好关闭二级缓存,如果有的话。



<property name="hibernate.jdbc.batch_size">20</property> 
<property name="hibernate.cache.use_second_level_cache">false</property>



但是,这不是绝对必须的,因为我们可以显式设置CacheMode来关闭与二级缓存的交互。


如果要将很多对象持久化,你必须通过经常的调用 flush() 以及稍后调用 clear() 来控制第一级缓存的大小。


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, same as the JDBC batch size
session.flush();
session.clear();
}
}
tx.commit();
session.close();





[b]Hibernate批量操作的三种方法:[/b]


[color=red][b]方法一(直接用HQL语句): [/b][/color]


由Query.executeUpdate()方法返回的整型值表明了受此操作影响的记录数量。注意这个数值可能与数据库中被(最后一条SQL语句)影响了的“行”数有关,也可能没有。一个大批量HQL操作可能导致多条实际的SQL语句被执行, 举个例子,对joined-subclass映射方式的类进行的此类操作。这个返回值代表了实际被语句影响了的记录数量。在那个joined-subclass的例子中, 对一个子类的删除实际上可能不仅仅会删除子类映射到的表而且会影响“根”表,还有可能影响与之有继承关系的joined-subclass映射方式的子类的表。



INSERT语句的伪码是: INSERT INTO EntityName properties_list select_statement.


要注意的是:只支持INSERT INTO ... SELECT ...形式,不支持INSERT INTO ... VALUES ...形式.


Session session=SessionFactory.openSession();  
Transaction tx=session.beginTransaction();
String hql = "update Customer set phone=Trim(phone)",
//String hql = "delete Customer where id < 5000",
//String hql = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery(hql).executeUpdate();
tx.commit();
session.close();




[color=red][b]方法二(利用服务器游标): [/b][/color]


此方法同样适用于检索和更新数据。此外,在进行会返回很多行数据的查询时, 你需要使用 scroll()方法以便充分利用服务器端游标所带来的好处。


Session session = sessionFactory.openSession();  
Transaction tx = session.beginTransaction();
//关掉缓存策略
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWARD_ONLY)
.setCacheMode(CacheMode.IGNORE);
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
session.update(customer);
}
tx.commit();
session.close();





[b][color=red]方法三(无状态session接口): [/color][/b]


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



在下面的例子中,查询返回的Customer实例立即被脱管(detach)。它们与任何持久化上下文都没有关系。


StatelessSession 接口定义的insert(),update()和delete()操作是直接的数据库行级别操作,其结果是立刻执行一条INSERT, UPDATE 或 DELETE 语句。因此,它们的语义和Session 接口定义的save(),saveOrUpdate()和delete()操作有很大的不同。


StatelessSession不参与hibernate的各种缓存,默认的隔离级别对他也不起作用,直接生成sql直接执行,类似jdbc。但是他需要自己去写事务提交,spring好像也拦截不到它


如果batch设置成100的话,那么会每一百次执行一次同步一次数据库


有一个注意的地方:如果表中的主键是identity的话,那么batch就会失效,直接用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();

标签:Hibernate4,Customer,缓存,批量,tx,...,customer,session,三种
From: https://blog.51cto.com/u_3871599/6139971

相关文章

  • 使用Jcom组件操作Visio批量导出图片
    [url]http://mncc.iteye.com/blog/367389[/url]在JAVA中使用JCOM和JXL注意要点:(1)在你的lib下要有jdom-1.0.jar,jxl-2.5.5.jar,jcom-2.2.4.jar,jcom.dl......
  • 三种javascript数组搜索的效率对比
    [b][color=red][size=x-large]结论:内置方法是最快的.[/size][/color][/b]//构造一个数组vararr=[];for(vari=0;i<=1000000;i++){arr.push('abcdefghigk'+i);}varv=......
  • B站全自动批量取消关注(浏览器执行脚本
    参考知乎文章:js小经验:如何快速取消关注B站(哔哩哔哩)所有up主?但是由于原脚本只能一页一页的手动批量取消关注,所以这里对脚本进行了修改为全自动取消:原脚本:varms=250;/......
  • css实现文本水平&垂直对齐的三种方式
    第一种:使用padding和text-align:center例如:.center{padding:100px0;border:1pxsolidgreen;text-align:center;} 第二种:使用line-heig......
  • 他惊了他惊了,批量翻译竟然那么容易!
    哈喽,大家好!我是与Excel/WPS表格“相爱相杀”的小编~当需要大量翻译表格中内容并将翻译结果依旧保存在表格中时,大家都怎么做呢?一个个复制粘贴到翻译网站吗? 其实根本不......
  • Linux cpio三种操作模式详解!
    cpio是一种数据备份与恢复工具,用于创建cpio档案文件,那么Linuxcpio三种操作模式是什么?分别是:copy-out模式、copy-in模式、copy-pass模式,接下来来看看详细的内容介绍。......
  • 在使用批量插入数据时报的错误
    :::infocom.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:YouhaveanerrorinyourSQLsyntax;checkthemanualthatcorrespondstoyourMySQLserver......
  • ansible批量执行输出所有账户
    [root@libin3]#catlibin.yml-hosts:task  gather_facts:no  tasks:    -name:fetch      shell:|     foriin`awk-F':''{if($......
  • 批量多次复制依次粘贴工具【编程语言:易语言】
    工具用途该工具用于复制多个文本后再批量多次粘贴,例如依次ctrl+c复制a,b,c文本后,再使用ctrl+v粘贴即可依次粘贴出c,b,a。如图所示现在也支持正序和导入功能了,更多功能看下......
  • Docker-批量删除REPOSITORY或TAG为<none>的镜像
    问题通过dockerimages命令查询本地镜像列表有可能看到repository和tag均为none的镜像,这种镜像在Docker官方文档中被称作danglingimages。原因根据官方解释,该镜像的......