最近在研究系统启动时将数据加载到内存非常耗时,想着是否有办法优化!经过日志打印测试发现查询时间(查询时间:将数据库数据查询到系统中并转为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)值转为小写)的更多相关文章

  1. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...

  2. MapReduce中一次reduce方法的调用中key的值不断变化分析及源码解析

    摘要:mapreduce中执行reduce(KEYIN key, Iterable<VALUEIN> values, Context context),调用一次reduce方法,迭代val ...

  3. 多线程与高并发(五)—— 源码解析 ReentrantLock

    一.前言 ReentrantLock 是基于 AQS 实现的同步框架,关于 AQS 的源码在 这篇文章 已经讲解过,ReentrantLock 的主要实现都依赖AQS,因此在阅读本文前应该先了解 AQ ...

  4. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  5. 【VUE】Vue 源码解析

    Vue 源码解析 Vue 的工作机制 在 new vue() 之后,Vue 会调用进行初始化,会初始化生命周期.事件.props.methods.data.computed和watch等.其中最重要的 ...

  6. ArrayList源码解析(二)

    欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html 自己学习ArrayList源码的一些心得记录. 继续上一篇,Arra ...

  7. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  8. CopyOnWriteArrayList源码解析

    Java并发包提供了很多线程安全的集合,有了他们的存在,使得我们在多线程开发下,可以和单线程一样去编写代码,大大简化了多线程开发的难度,但是如果不知道其中的原理,可能会引发意想不到的问题,所以知道其中 ...

  9. [Java并发] AQS抽象队列同步器源码解析--独占锁释放过程

    [Java并发] AQS抽象队列同步器源码解析--独占锁获取过程 上一篇已经讲解了AQS独占锁的获取过程,接下来就是对AQS独占锁的释放过程进行详细的分析说明,废话不多说,直接进入正文... 锁释放入 ...

随机推荐

  1. 【原】简单shell练习(六)

    1.shell获取进程号并杀掉该进程 kill - $(ps -ef | grep node| grep -v grep | awk '{print $2}') 解析: ps (processStat ...

  2. 并行效果&迭代器

    具体文章:ALEX的文章 https://www.cnblogs.com/alex3714/articles/5765046.html 串行的并行效果: import time def consume ...

  3. 使用YUM安装软件时提示PackageKit睡眠中解决方法!

    报错如图所示: 解决方法一:移除var/run/yum.pid文件 方法二:直接杀掉进程号 报错的时候会跟进程号 直接利用kill   -9  +进程号

  4. 国外最受欢迎的15个BT下载网站

    1.EYH.BIZ 海盗湾(The Pirate Bay)现在在中国成立的一个分部 www.eyh.biz 一个提供BT种子文件和链接,以方便使用BT协议的对等文件共享网站.该网站于2003年在瑞典创 ...

  5. RestTemplate HttpMessageConverter报错的解决方案no suitable HttpMessageConverter

    错误 no suitable HttpMessageConverter found for response type and content type [text/html;charset=UTF- ...

  6. 「JSOI2011」任务调度

    「JSOI2011」任务调度 传送门 一开始还在想写平衡树,看到 \(\text{TRANS}\) 操作后就晓得要用可并堆了. 这题好像就是个可并堆的板子题??? ADD 直接往对应的对里面加元素 D ...

  7. 计算机基础 - 时间戳(timestamp)位数

    分为10位数字(ten digit)和13位(thirteen digit)数字 1. Unix, Python为10 time +%s import time time.time() 2. Java ...

  8. 奖学金(0)<P2007_1>

    奖学金 (scholar.pas/c/cpp) [问题描述] 某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金.期末,每个学生都有3门课的成绩:语文.数学.英语.先按总分 ...

  9. 吴裕雄--天生自然数据结构与算法:java代码实现常用数据结构——链表Linked List

    class Node{ // 定义节点类 private String data ; // 保存节点内容 private Node next ; // 表示保存下一个节点 public Node(St ...

  10. day22-Python运维开发基础(正则函数 / 异常处理)

    1. 正则函数 # ### 正则表达式 => 正则函数 import re # search 通过正则匹配出第一个对象返回,通过group取出对象中的值 strvar = "5*7 9 ...