最近使用Eclipse插件制作一个项目管理工具,由于涉及的数据结构比较复杂,简单的展示一棵导航树就涉及到至少20个表关联查询(其中包含大量的自关联及循环关联),刚开始数据量较小时尚可应付,当运行一段时间后,数据量达到万级以后,性能就相当差了,仔细看了一下,由Hibernate翻译过来的一条SQL就显示了十屏以上,汗一个先,所以下定决心优化一下。
首先想到是数据库层面的优化,由于数据结构已经固定,无法再通过增加删除表来优化,剩下的策略只能是加加索引,增加视图来减化复杂性(要命的是视图无法作更新操作),但收效甚微。
其次想到的是使用Hibernate的二级缓存来优化性能,但由于CS应用的特点决定,数据操作一定是发生在并发的环境中,所以贸然打开二级缓存会带来更大的麻烦(所谓的脏数据),所以基本放弃了,试着针对几个常量表开了只读的二级缓存,但效果依然不明显。
最后想到的是使用原来作WEB应用时常用的Open Session In View方式来作基于长事务的懒加载,但与WEB应用不同,WEB应用可以严格的界定事务边界,简单的加一个Filter就可以实现了,但CS架构的应用没有明显的边界,数据的查询和更新发生在整个生命周期的任何时刻,想破了头也没想到好的方法来实现,至此基本打算放弃了。
这几天翻看Hibernate源码,发现Hibernate实现懒加载并不强制要求被加载对象与宿主对象必须在同一个事务中,只要有一个可用的Session,并且在这个Session的上下文(其实就是Session的一级缓存)中注册相应的持久类信息即可,而这个Session是否与被加载对象的宿主处在同一个事务中,Hibernate并不关心,基于此准备实现一个跨事务的懒加载机制来简化复杂业务下的大数据加载问题。
protected Object initialize(final Object proxy) {
if (proxy instanceof HibernateProxy)
return initializeHibernateProxy((HibernateProxy) proxy);
else if (proxy instanceof PersistentCollection)
return initializePersistentCollection((PersistentCollection) proxy);
return proxy;
}
private Object initializePersistentCollection(final PersistentCollection persistentCollection) {
if (persistentCollection.getRole() != null && !persistentCollection.wasInitialized() && ((AbstractPersistentCollection) persistentCollection).getSession() == null) {
return getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
final SessionImplementor sessionImplementor = (SessionImplementor) session;
final CollectionPersister collectionPersister = sessionImplementor.getFactory().getCollectionPersister(persistentCollection.getRole());
sessionImplementor.getPersistenceContext().addUninitializedDetachedCollection(collectionPersister, persistentCollection);
persistentCollection.setCurrentSession(sessionImplementor);
persistentCollection.forceInitialization();
sessionImplementor.getPersistenceContext().clear();
persistentCollection.unsetSession(sessionImplementor);
return persistentCollection;
}
});
}
return persistentCollection;
}
private Object initializeHibernateProxy(final HibernateProxy proxy) {
final LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer();
if (lazyInitializer.isUninitialized() && lazyInitializer.getSession() == null) {
return getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
lazyInitializer.setSession((SessionImplementor) session);
lazyInitializer.initialize();
lazyInitializer.unsetSession();
return proxy;
}
});
}
return proxy;
}
按道理,为了尽可能的减少对原有结构的侵入,应该对所有实体类的GET方法作代理,判断数据是否已被加载,如果没加载,则调用initialize方法先加载数据后再返回,可是我至今没有发现Hibernate提供类似的Intercepter,应该是可以使用第三方的代理来实现,这块我再研究一下,目前的实现方式是对实体类的GET方法硬编码:
public ComponentTypeBean getComponentTypeBean() {
return (ComponentTypeBean) initialize(componentTypeBean);
}
@SuppressWarnings("unchecked")
public Set<PageComponentBean> getPageComponentBeans() {
return (Set<PageComponentBean>) initialize(pageComponentBeans);
}
显然这样作可以实现预期效果,但并不理想,不知道Hibernate是否提供了实体类的GET代理,等有时间再翻一下文档。
至此,基于跨事务的懒加载已经实现,当然方法可能用的并不是很正确,希望有高人再指点一下。经测试实际效果非常理想,总结一下使用跨事务懒加载:
好处:
1.原来长篇大论的HQL全部可以简化为单表查询了,换句话说再也不用费尽脑汁的去想需要写几个join fech了,只要查询出主表数据即可,随时随地调用GET方法即可实现从表数据的懒加载,彻底告别could not initialize proxy - no Session,could not initialize proxy - the owning Session was closed等异常。
2.将大SQL拆成若干个单表查询的小SQL,在特定环境下会为显著提升系统性能,改善用户体验。
坏处:
1.会造成SQL量增大,用的不好反而会造成系统性能下降。
2.与Open Session In View不同,跨事务懒加载破坏了Hibernte原有的缓存体系,无法发挥事务内缓存带来的性能提升。
原文地址: http://www.coolfancy.com/log/31.html
更多精彩原创文章请关注笔者的原创博客:http://www.coolfancy.com
分享到:
相关推荐
PaddleTS 是一个易用的深度时序建模的Python库,它基于飞桨深度学习框架PaddlePaddle,专注业界领先的深度模型,旨在为领域专家和行业用户提供可扩展的时序建模能力和便捷易用的用户体验。
白色大气风格的乐器爱好者网站模板下载.zip
海外派遣员工管理守则
flowable-demo-master
内容概要:本文档详细介绍了一个图书馆管理系统的数据库课程设计。内容涵盖需求分析、数据库设计、SQL实现、前端实现及系统测试等环节。项目旨在支持图书借阅、归还、图书信息管理、用户管理等功能。数据库设计包括三个主要表:用户表(Users)、图书表(Books)和借阅记录表(BorrowRecords)。通过具体示例演示了表的创建、数据插入及查询操作。 适用人群:适合正在学习数据库设计或从事数据库相关工作的学生和技术人员。 使用场景及目标:①学习如何进行需求分析,确定系统的功能和数据需求;②掌握数据库设计方法,绘制ER图并转换为具体的表结构;③编写SQL语句,实现数据的增删改查操作;④实现前端页面,完成与后端的交互;⑤进行系统测试,确保各项功能正常运行。 其他说明:此文档不仅提供了理论知识,还给出了详细的代码示例,非常适合动手实践。建议在学习过程中结合文档中的示例,动手实现数据库设计、SQL操作和前端页面,从而加深对数据库技术的理解。
白色风格的手机网站模板下载.rar
白色淡雅风的商务企业网站模板下载.zip
白色大气风格的企业站通用整站网站源码下载.zip
PCle AI加速卡在医疗影像诊断中的应用.docx
Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
白色大气简洁的时装模特企业网站模板下载.zip
西门子PLC 1214C 做的压机控制 可以在触摸屏上任意编辑压装逻辑 该程序为一台设备的完成程序 包含很多工能块 压机控制程序+汇川PN伺服块+脉冲控制块+以太网TCP功能块 + 气缸块+托盘坐标计算块+基恩士扫码器SR1000块+模拟量功能块 所有功能块都是基于模块话编程思路编辑功能块都是SCL语言 可移植性强 一个公式套用所有功能块 可以直接将IO引脚做成触摸屏库关联 编写思路新颖,有助于提高编程能力
通过分析,了解谷歌应用商店app的总体情况。
“开学第一课”小学儿童教育家长会宣传模板
内容概要:本文涵盖了大地测量的基本概念、任务和特点,大地测量系统与参考框架,常用坐标系及其转换方法,传统大地控制网的布设原则,光学经纬仪和全站仪的使用与检验,水平角和三角高程测量的观测方法,以及导线测量的技术要点。文中还提供了多个例题,帮助考生理解和掌握关键知识点。 适合人群:具备一定测绘基础,准备参加注册测绘师资格考试的专业技术人员。 使用场景及目标:用于备考注册测绘师资格考试,提高大地测量领域的专业知识和技能,掌握具体的测量方法和技术细节。 阅读建议:此讲义内容详实,涵盖了大量实用的技术细节,建议结合实际测量工作和练习题进行学习,以加深理解和应用能力。
白色简洁风的设计企业网站模板下载.zip
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;
白色大气风格的恐龙化石博物馆网站模板下载.zip
白色简洁风格的餐厅会员登录框源码下载.zip
白色创意风格的单反爱好者网站模板下载.zip