摘要:
Hibernate并没有为巨型数据集合提供良好的帮助这也许是开发者认为这样没有太大必要反而增加Hibernate框架复杂性的缘故吧最近在Hibernate的官方坛子上看到Gavin写给初级用户的understand FlushModeNEVER并参考了一下Stripes项目(本人时常关注的时髦项目)作者Tim的blog在阅读两位大家言论后和大家share一下
一案件背景
图片来自于电影《天生杀人狂》
Hibernate并没有为巨型数据集合提供良好的帮助这也许是开发者认为这样没有太大必要反而增加Hibernate框架复杂性的缘故吧于是极大数据量==批量处理Hibernate/java不是批处理的最佳场所的观念在Hibernate开发中大行其道有些开发者甚至直接利用Hibernate建立session获取其connection进而进行jdbc操作Jdbc并不是古董但在Hibernate中再次call它难免有些令人无奈最近在Hibernate的官方坛子上看到Gavin写给初级用户的understand FlushModeNEVER并参考了一下Stripes项目(本人时常关注的时髦项目)作者Tim的blog在阅读两位大家言论后和大家share一下
二性能杀手何在?
图片来自于电影《这个杀手不太冷》
Tim在其Blog写道我目前的DNA重组系统具有复杂而海量的OLTP数据对付这些在内存的复杂对象(数千个)的方式是依赖用户接口(非批量处理)来实现用例驱动这句半开玩笑的话是我想起了那男耕女织的生产力低下的生活真的让每个开发者都使用算盘运算吗?
sessionsetFlushMode(FlushModeNEVER);
这条语句及其简单但解决了大问题它告知Hibernate session无论何时也不要flush任何的状态变化到数据库除非开发者直接调用sessionflush()听上去很合乎逻辑但它为何在一些场景中对性能影响甚深而在其他的场景中却好似轻如鹅毛般?
在Tim的项目中存在着一个十分典型的case(我也不大了解生物这不能怪我)在实验中利用PCR Primers对遗传基因(genes)和DNA中的核苷酸序列(exons)这里的PCR Primers是在PCR处理过程中用于检测DNA片段的物质对不起大家本人对生物学词汇实在无能为力检测匹配过程大致分为以下步
.发现本次实验中所有exons(个数在个以上)
.查询本次实验所有已经排序的PCR Primers
.查询本次实验所有待排序的PCR Primers
.得到与exons对应的Primers找出那些无需转换的部分
.在系统中为无需转换的区域查询所有可能的PCR Primers
.测试每个primer找出最佳exons匹配者(Primer)
.保存找出的Primer
不用担心步骤细节不大明白也不会影响后面的理解
由于domain model极其海量在第步我们可能在一个session中排序个对象而在步的查询将带来个附加对象有趣之处在于当执行第步将对象save到数据库时没有一个前面装载的对象被修改过整个实验的目的就是仅仅获得这个对象
在回顾了Tim的生物学场景之后让我们重新回到FlushModeNEVER的讨论上来吧你可能认为既然直到最后一步都没有修改或是持久化任何东西那么改变flush模式将收效甚微当然这是不正确的未参透实质的理解实际上在上面流程的起始设置Never这个flush模式在流程终点手动flush将节省一半的run time请注意这里仅提到了run time而没有将内存IO计算在内
三这个杀手不太冷
图片来自于电影《黑衣人》
幸好这个杀手不太冷!这都归结于Hibernate的髒检查(dirty checking)每次装载一个对象到内存(不能去evict它)时session始终跟蹤它的修改于是每次对数据的查询session都将跌代所有的session中的对象并检查髒数据将髒数据flush到数据库Hibernate这样做的良苦用心是为了确保在执行查询之前所有可能影响查询的变化都被提交到数据库这对零星数据量的应用来讲不足为言但面对数千个对象和千余次的查询来讲它将使性能的真正杀手
了解真相后我们可以使用sessionsetFlushMode(FlushModeNEVER)语句将在查询时不需髒检查的数据(生物实验中的Primers)标识髒数据这样Hibernate无处不在的代理机制将被欺骗直接将它添加到髒数据列表(列表中的数据不会被flush到数据库)中这样杀手就会因无处遁形而自动消失了
四打造制胜武器
图片来自于电影《致命武器》
在读完这个简短的案件后我们也学到了如何在一个session中读取查询大量数据对象情况下的制胜武器 FlushModeNEVER当然要记住在此过程中你不可以修改这些数据不然就真的把数据搞髒了
使用武器秘诀如下
FlushMode previous = sessiongetFlushMode();
sessionflush(); // who knows what been done till now
sessionsetFlushMode(FlushModeNEVER);
// Do some querying
// Do some more querying
// Really load up that session
// Execute a few more queries
// Write back to some tables
sessionflush();
sessionsetFlushMode(previous);
五联系作者
cleverpig:
Tim的Blog: