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

    文章参考至 一.前言&索引 CSS Shapes布局可以实现不规则的文字环绕效果,需要和浮动配合使用. 兼容性如下图: 还是很不错的,移动端可用,内部中后台项目可用. CSS shapes布局 ...

  2. Educational Codeforces Round 74 (Rated for Div. 2)E(状压DP,降低一个m复杂度做法含有集合思维)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;char s[100005];int pos[ ...

  3. 与英特尔分道扬镳,苹果的5G业务掉队了吗?

    5G概念已经大热,越来越多的厂商推出相关产品,中国骄傲之华为不仅在5G通信标准制定方面参与感非常强,也先于竞争对手推出5G智能终端,连同三星/Vivo等也纷纷推出5G终端,而作为智能手机市场绝对的利润 ...

  4. js 子窗口调用父框框方法

    父窗口 子窗口

  5. nyoj 67

    三角形面积 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 给你三个点,表示一个三角形的三个顶点,现你的任务是求出该三角形的面积   输入 每行是一组测试数据,有6个 ...

  6. P1025数的划分

    P1025数的划分 #include <iostream> using namespace std; int n,k; int cnt; void dfs(int s,int step,i ...

  7. 吴裕雄--天生自然ORACLE数据库学习笔记:过程、函数、触发器和包

    create procedure pro_insertDept is begin ,'市场拓展部','JILIN'); --插入数据记录 commit; --提交数据 dbms_output.put_ ...

  8. git github 对代码的管理

    参考:https://www.cnblogs.com/feynman61/p/9005252.html 一.Git 对远程仓库版本回退 场景: 同事 a.b 同时修改了代码,提交到仓库 同时 c 不熟 ...

  9. LeetCode633. Sum of Square Numbers(双指针)

    题意:给定一个非负整数c,确定是否存在a和b使得a*a+b*b=c. class Solution { typedef long long LL; public: bool judgeSquareSu ...

  10. HttpClient 以post的方式发送请求(由于请求参数太多所以改成以post提交表单的方式)

    1:Util类方法 /** * 发送 Post请求 * * @param url * @param reqXml * @return */ public static String post(Stri ...