最近在研究系统启动时将数据加载到内存非常耗时,想着是否有办法优化!经过日志打印测试发现查询时间(查询时间:将数据库数据查询到系统中并转为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. springboot 打包成jar

    1.pom.xml配置 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins< ...

  2. 洛谷P2142 高精度减法 题解

    想找原题请点击这里:传送门 原题: 题目描述 高精度减法 输入格式 两个整数a,b(第二个可能比第一个大) 输出格式 结果(是负数要输出负号) 输入输出样例 输入 复制 输出 复制 说明/提示 %数据 ...

  3. MavenProfile简介

    在我们平常的java开发中,会经常使用到很多配制文件(xxx.properties,xxx.xml),而当我们在本地开发(dev),测试环境测试(test),线上生产使用(product)时,需要不停 ...

  4. 【JavaWeb】导入Excel并进行校验

    一.需要实现的目标 1.界面编写 2.导入表读取表名,进行校验,后台匹配(判断此表的名称是否能够模糊匹配上) 3.确定表存在,读取其中的数据,暂存 4.正则表达式数据校验(判断是否已存在,数据是否符合 ...

  5. 「CQOI2009」中位数

    「CQOI2009」中位数 传送门 这道题将会用到一点桶的思想. 首先我们可以在排列中先找到 \(b\) 的位置(找不到的话就直接输出 \(0\)). 然后我们从 \(b\) 的位置(设为 \(p\) ...

  6. AbstractQueuedSynchronizer AQS源码分析

    申明:jdk版本为1.8 AbstractQueuedSynchronizer是jdk中实现锁的一个抽象类,有排他和共享两种模式. 我们这里先看排他模式,共享模式后面结合java.util.concu ...

  7. 面试问题之——给你图片的url,你能知道它所占的字节空间吗?

    从一个需求说起 这标题起得有点标题党,实际情况是我最近在做一个公司内部工具时,遇到了这么一个需求,给定一个静态资源站点上某张图片的url(比如https://a.xxxcdn.com/demo.jpg ...

  8. SpringBoot与Lombok

    Lombok 在项目中使用Lombok可以减少很多重复代码的书写.具体详细资料可以浏览 https://blog.csdn.net/motui/article/details/79012846 一.引 ...

  9. .net core 2.1控制台使用Quartz.net实现定时任务执行

    权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_33435149/article/de ...

  10. luogu P2704 炮兵阵地(经典状态压缩DP)

    方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解. 求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于 ...