• 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

          

        

        

      

    Wait for the flying eagles Believe that I will succee and just stack to it_Mr.Liu
  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/liu-eagles/p/7860476.html
Copyright © 2020-2023  润新知