hibernate部分源码解析and解决工作上关于hibernate的一个问题例子(包含oracle中新建表为何列名全转为大写且通过hibernate取数时如何不用再次遍历将列名(key)值转为小写)
最近在研究系统启动时将数据加载到内存非常耗时,想着是否有办法优化!经过日志打印测试发现查询时间(查询时间:将数据库数据查询到系统中并转为List<Map>或List<*.Class>,下面将全部针对转化类型为List<Map>进行分析)居然和数据加载时间一样长(加载时间:将查询到的数据组装成系统中业务所需要的数据模型,基本调用了所有key为get/set方法)。由此我觉得系统查询时间是有优化的空间的,并通过两个周末对此进行了研究学习并优化此问题,一下是整体流程:
1、疑问点
查询时间为何耗时如此耗时
1.1、分析问题
系统DAO层使用的是hibernate,但是经过查看代码后发现与我想象中不一样的代码,如下:
Connection con = arg0.connection();//此处调用来了connection方法,而查看源码后发现此方法已经被弃用了(只是取connection的方法换了一种不影响)
Statement state = con.createStatement();
ResultSet resultSet=null;
try{
resultSet = state.executeQuery(sql[0]);
//遍历resultset,去除columnName和value——在遍历取columnName时将其转为小写,统一代码中map的key值,方便在加载数据时取数,此处的解释在后边分析中会用到
此处通过session的到jdbc的连接connection,然后通过jdbc从数据库取数(感觉因为再次需要单独遍历一遍result,所以耗时多)!!!接下来疑问产生了,既然用了hibernate为什么还要通过jdbc取,为什么不直接通过session.createsqlquery的得到query,然后通过query.list直接获取所需list<Map>hibernate方式取数?
1.2、解决并验证问题
接下来我通过修改代码使用两种方式同时进行取数并打印取数时间,发现通过hibernate方式取数耗时仅仅是通过jdbc取数耗时的一半,本来问题就此解决了,但新的一个问题出现了!!!!
2、新问题出现
通过hibernate方式取出的list<Map>的key值全为大写!!!
2.1、分析下问题_1
list<Map>的key值全为大写不符合系统现在已有的取数逻辑,修改已有的取数代码会很耗时切不好,重新遍历使用String.tolower方法的话岂不是和通过jdbc取一样需要重新遍历,耗时的问题就决绝不了!那此时我想到的决绝方案是:重写hibernate的createsqlquery方法,让其在调用源码中原有的遍历方法时对其进行转换。
2.2、解决并验证问题
2.2.1 关于oracle建表时列名写的小写
oracle建表时列名写的小写,为何建表后列名变为大写!且通过hibernate或jdbc取数时并没有做关于列名大小写转换的控制。
之前没有注意到这类问题,在新建表时我是不会关注列名大小写的,大牛们应该会关注吧!!其实很疑问,以我写sql的习惯,我的列名应该都是小写,为什么建好后查询时列名全为大写了!此处我查了相关资料,发现如果sql中列名没有加引号,oracle会默认将列名转为大写!!!!
2.2.2 关于重写SqlQueryImpl.createsqlquery的一个内部类_在此内部类中遍历取出的数据进行封装的
我重写了此方法,红色部分为修改处。如下:
/**
* Warning: adds new parameters to the argument by side-effect, as well as
* mutating the query string!
*/
protected String expandParameterLists(Map namedParamsCopy) {
String query = this.queryString;
Iterator iter = namedParameterLists.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
query = expandParameterList( query, ((String) me.getKey()).tolower(), (TypedValue) me.getValue(), namedParamsCopy );
}
return query;
}
在此处我重写了这个内部类,但我想要调用我重写的内部类,我必须new我自己重写的SqlQueryImpl类;但是如果new SqlQueryImpl的话需要很多hibernate的内部类型参数,对于这些参数我可以说是 非常不了解!但如果不想new SqlQueryImpl的话,我发现就必须重写整个hibernatejar包,从最开始的session就调用自己重写的!!这是不可行的,那我就只能研究new SqlQueryImpl的所需参数了,这里我看了一下午hibernate源码,可以说也提升了我对hibernate源码的整体框架有了部分的了解,在下篇博客中我会对x下午所了解到的hibernate源码涉及到的框架进行分析。
在研究过源码后我发现了query的一个变量ResultTransformer,这事我才想到调用query.list前是需要设置query.setResultTransformer;变量ResultTransformer顾顾名思义应该就是控制查询结果的类型的,如下:
Query query = session.createSQLQuery(sql);
query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
// query.setResultTransformer(CriteriaSpecificationAddMapToLower.ALIAS_TO_ENTITY_MAP_KEY_TOLOWER);//此处是我自己封装的类型
list = query.list();
经过查看源码发现就是此参数对返回值类型进行控制的(这里的推论还没来得及验证,是根据源码得到了理论!)。那我们研究下这个参数吧:
/**
* @author Gavin King
*/
public class AliasToEntityMapResultTransformer implements ResultTransformer { public Object transformTuple(Object[] tuple, String[] aliases) {
Map result = new HashMap(tuple.length);
for ( int i=0; i<tuple.length; i++ ) {
String alias = aliases[i];
if ( alias!=null ) {
result.put( alias.tolower, tuple[i] );
}
}
return result;
} public List transformList(List collection) {
return collection;
}
}
这是这个类型参数的一个实现类,是将结果转为标准list<Map>型!那我们只需要重写此方法就可以了~~~~~~~~红色部分为重写部分
理论上这个问题就得到解决了,但实际中并未验证,需要大数据量才能验证,到工作日时我会利用下班时间进行测试,并将测试结果添加到下方。
由于对hibernate源码没有研究过,所以在解决此问题时走了很多弯路,但也在弯路中更加细致的了解了hibernate源码相关知识和部分源码框架以及已经部分方法为何启用,新替代方法是什么等知识点,在下片博客中我会记录下自己一步步走来的脚印~
加油~Mr.liu
hibernate部分源码解析and解决工作上关于hibernate的一个问题例子(包含oracle中新建表为何列名全转为大写且通过hibernate取数时如何不用再次遍历将列名(key)值转为小写)的更多相关文章
- 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...
- MapReduce中一次reduce方法的调用中key的值不断变化分析及源码解析
摘要:mapreduce中执行reduce(KEYIN key, Iterable<VALUEIN> values, Context context),调用一次reduce方法,迭代val ...
- 多线程与高并发(五)—— 源码解析 ReentrantLock
一.前言 ReentrantLock 是基于 AQS 实现的同步框架,关于 AQS 的源码在 这篇文章 已经讲解过,ReentrantLock 的主要实现都依赖AQS,因此在阅读本文前应该先了解 AQ ...
- 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试
机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...
- 【VUE】Vue 源码解析
Vue 源码解析 Vue 的工作机制 在 new vue() 之后,Vue 会调用进行初始化,会初始化生命周期.事件.props.methods.data.computed和watch等.其中最重要的 ...
- ArrayList源码解析(二)
欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html 自己学习ArrayList源码的一些心得记录. 继续上一篇,Arra ...
- Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- CopyOnWriteArrayList源码解析
Java并发包提供了很多线程安全的集合,有了他们的存在,使得我们在多线程开发下,可以和单线程一样去编写代码,大大简化了多线程开发的难度,但是如果不知道其中的原理,可能会引发意想不到的问题,所以知道其中 ...
- [Java并发] AQS抽象队列同步器源码解析--独占锁释放过程
[Java并发] AQS抽象队列同步器源码解析--独占锁获取过程 上一篇已经讲解了AQS独占锁的获取过程,接下来就是对AQS独占锁的释放过程进行详细的分析说明,废话不多说,直接进入正文... 锁释放入 ...
随机推荐
- BOSS标准版-电话收费结账明细费用sql语句
明细费用页面-所在jsp路径-:/EtcomWeb_BZvx/WebRoot/hfys/manage/telCharge/detailInfo.jsp exec Hfys_Sp_CaculCharge ...
- python知识点总结以及15道题的解析
先看知识点总结 一.序列操作符x in s 如果x是列表s的元素,返回True,否则Falses + t 连接两个序列s和ts*n或者n*s 将序列s复制n次s[i] 返回s中第i元素s[i:j]或s ...
- WEB安全 - XSS,CSRF
1. CSRF参考 https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/ https://en.wikipedia.org/wiki ...
- sql server删除重复的数据保留一条
DELETE FROM [TCX_1710_SHZJ].[dbo].[PR_BindingTray] WHERE 1=1 AND SNum in (SELECT * FROM ( (SELECT SN ...
- SQL SERVER2005自动备份 2012.3.29
要想在 SQL2005上进行数据库的自动备份必须把sql server的SQL Server Agent服务开启,否则是无法进行自动备份的 启动完成之后,用户可以直接在“管理”下面的“维护计划”选项来 ...
- SpringBoot中普通类无法通过@Autowired自动注入Service、dao等bean解决方法
无法注入原因: 有的时候我们有一些类并不想注入Spring容器中,有Spring容器实例化,但是我们又想使用Spring容器中的一些对象,所以就只能借助工具类来获取了 工具类: package com ...
- STM32的程序升级
IAP基础参考http://www.eeworld.com.cn/mcu/2018/ic-news112042038.html https://blog.csdn.net/tq384998430/ar ...
- Python的常用库
读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz写的最富盛名的http库.每个Python程序员都 ...
- 计划任务之一次性计划任务(at)和周期性计划任务(crontab)(重点)
一:知识要点 ----计划任务的意义----计划任务分类----用户计划任务crontab----系统计划任务----计划任务使用注意事项----anacron服务介绍 二:计划任务的意义计划任务 - ...
- springboot之快速创建项目
1.选择创建新项目: 2.选择spring initializr,然后next 3.填写项目元数据,然后next 4.选择项目依赖,然后next 5.点击finish,完成项目创建