zoukankan      html  css  js  c++  java
  • 通过query解析hibernate中的resultTransformer

    转载 http://www.iflym.com/index.php/code/resolve-hibernate-result-transformer-by-query.html  

    任何包装jdbc的框架,都离不开将最终的数据封装成java对象的一个过程。在jdbc中,取得的数据被封装在resultset中,通过迭代resultset来一次次的取得相应的字段和数据值。数据库框架始终需要解决的问题在于将resultset中的字段名称信息和相应的字段值对应起来,然后封装成对象,最后将所有的对象形成一个集合,并最终返回给调用者。
        任何数据库框架都逃不过这中间的处理逻辑,只不过如何将这些逻辑分散在上下的处理中。在Hibernate中,同样也有类似的东西,这个接口就叫做ResultTransformer。

        Transformer的定义如下:

    public interface ResultTransformer extends Serializable 

    {      

    public Object transformTuple(Object[] tuple, String[] aliases);      

    public List transformList(List collection); 

        其中第一个方法transformTuple,即是如何处理从数据库查询出来的字段值(可能经过了二次处理)和相对应的字段名称值,比如将字段值和字段名称组合成一个map。字段值,即在查询过程中查询的字段列表,而字段名称即是在查询时select的名称。
        第二个方法transformList,提供了对于从数据库返回结果,进行了封装之后,再对封装之后的数据列表进行最后一次处理。如进行去重等。

        为了说明ResultTransformer在Hibernate中的运用,我们从Hibernate中的查询入手,看ResultTransformer如何在其中运用的(以Hibernate3.6.3版本为例,在代码中不显示不必要的代码)。

        由类QueryImpl中的list入手:

    public List list() throws HibernateException {             

    return getSession().list(expandParameterLists(namedParams), getQueryParameters(namedParams));     

        注意上面代码中的getQueryParameters调用,这里会将传递给query的所有参数进行封装,包括传递给query的resultTransformer。如果我们使用query.setResultTransformer传递给query,在调用时这里就会传递给相应的函数,并生成一个QueryParameters对象。
        接下来看sessionImpl中的实现:

    public List list(String query, QueryParameters queryParameters) throws HibernateException 

    {         

    HQLQueryPlan plan = getHQLQueryPlan( query, false );             

    results = plan.performList( queryParameters, this );         

    return results;     

        以下代码将查询语句封装成一个查询计划,并执行该计划,返回一个查询结果。进入方法实现,类HQLQueryPlan的performList方法:

    public List performList(QueryParameters queryParameters,SessionImplementor session) throws HibernateException {
            List combinedResults = new ArrayList();
            translator_loop: for ( int i = 0; i < translators.length; i++ ) {
                List tmp = translators[i].list( session, queryParametersToUse );
                    combinedResults.addAll( tmp );
            }
            return combinedResults;

        } 

        以上代码会调用一个叫QueryTranslator的实现,即将hql转化为sql并进行查询操作。进入实现类QueryTranslatorImpl类的list方法:

    public List list(SessionImplementor session, 

    QueryParameters queryParameters) throws HibernateException 

    List results = queryLoader.list( session, queryParametersToUse ); 

    return results; 

        以上代码会调用最终的查询逻辑实现即queryTranslator的最终数据库加载逻辑去查询,进入实现类QueryLoader的list方法:

     public List list(SessionImplementor session,QueryParameters queryParameters) throws HibernateException {

            return list( session, queryParameters, queryTranslator.getQuerySpaces(), queryReturnTypes );
        }
     
        protected List list( final SessionImplementor session,final QueryParameters queryParameters, final Set querySpaces, final Type[] resultTypes) throws HibernateException {
                return listIgnoreQueryCache( session, queryParameters );
        }
     
        private List listIgnoreQueryCache(SessionImplementor session, QueryParameters queryParameters) {
            return getResultList( doList( session, queryParameters ), queryParameters.getResultTransformer() );
        }

         以上3个方法是一些内部实现逻辑,这里就不深究了。最重要的是最后的getResult方法和里面的doList方法。其中doList即是最终的数据库查询实现,以及初步的对象转化(比如from 类查询时,会将数据结果转换成一个dom对象)。然后将结果集交到getResultList中进行处理,即到了我们最重要的resultTransformer处理了。

    protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
            HolderInstantiator holderInstantiator = buildHolderInstantiator( resultTransformer );
            if ( holderInstantiator.isRequired() ) {
                for ( int i = 0; i < results.size(); i++ ) {
                    Object[] row = ( Object[] ) results.get( i );
                    Object result = holderInstantiator.instantiate(row);
                }......
                    return resultTransformer.transformList(results);
            }

        } 

        在上面的地方,这里出现了一个关键的类HolderInstantiator,就是根据resultTransformer来处理数据。首先会将返回的数据值(默认即为object数组)进行实例化为一个对象,就是将数组转换为对象,这里面就会调用我们transformer第一次转换数据了,即将数据库返回数据转换为需要的数据:

    public Object instantiate(Object[] row) {
            if(transformer==null) {
                return row;
            } else {
                return transformer.transformTuple(row, queryReturnAliases);
            }

        } 

        接下来就进行第二次处理,如果需要去重,就将list中的对象集合装入set,再转换回来进行去重处理。最后就是我们所需要的结果了。

        在这些处理当中,并不是每次处理都传递了resultTransformer的。对于没有resultTransformer的情况,Hibernate在内部已经进行了处理。如果我们需要查询一个domain对象,Hibernate就会使用entityKey来解析数据;如果查询的是属性列表,即是使用默认的object数组来装结果。但一旦设置了resultTransformer,就是将上面查询的结果进行处理了。如将object数组转换成其它格式,如list格式,或者map格式(这一种用得最频繁,即经常使用的AliasToEntityMapResultTransformer).。
        Hibernate使用了静态单态的模式来封装相应的resultTransformer实现,当需要相应的数据时,即可直接通过公共的静态字段进行获取和传递(而且也是惟一的手段)。如通过ResultTransformerImpl.INSTANCE或通过Transformers.静态字段引用来获取相应的resultTransformer,最终传递给query,criteria等,以达到获取数据的目的。

  • 相关阅读:
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    拦路虎
    拦路虎:jQuery
    图片百分百问题 z-index问题
    惠头无忧——浏览器兼容性
    响应式设计
    老子的第一篇博客
    less 学习 (计划终于执行了啊,不再拖延了)
    工作拦路虎
  • 原文地址:https://www.cnblogs.com/chenying99/p/2709029.html
Copyright © 2011-2022 走看看