通过query解析hibernate中的resultTransformer

任何包装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等,以达到获取数据的目的。

转载请标明出处:i flym 本文地址:https://www.iflym.com/index.php/code/resolve-hibernate-result-transformer-by-query.html

时间: 2024-10-13 08:04:47

通过query解析hibernate中的resultTransformer的相关文章

【Hibernate】解析hibernate中的缓存

Hibernate中的缓存一共有三种,一级缓存.二级缓存.查询缓存.缓存除了使用Hibernate自带的缓存,还可以使用redis进行缓存,或是MongoDB进行缓存. 所使用的Demo: User.java文件 package cn.test.bean; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.T

解析Hibernate中的持久化—ORM(转载)

最近一直在学习Hibernate,首先说一下Hibernate出现的原因吧,Hibernate是因为MVC的分层体系结构的出现,即数据持久层(模型层)的出现,持久层是在MVC三层架构的基础上提出来的,在提出持久层之前,业务逻辑层在实现业务逻辑的同时,还需要访问数据库,这样就为业务逻辑的扩展怎家了难度,有了持久层,业务逻辑层只需要负责业务逻辑的实现,对数据的交给持久层,使每一段业务逻辑代码的目的都更明确,这样操作就更简单了. 如下图:增加了持久层的MVC分层结构 Hibernate作为一个中间件,

(转)Hibernate中的Query一些基本用法

/*** 添加*/public void save(Stu stu){ try { tran=this.GetSession().beginTransaction(); this.GetSession().save(stu); tran.commit(); } catch (HibernateException e) { throw e; }finally{ this.CloseSession(); }} /*** 使用HQL全查询*/public List getallbyHQL(){ Lis

hibernate 中的query的分页查询

//方法描述:根据会员名称和页容量分页查询代理人 public List<HbUser> findUserByPage(int page,int pageSize, String userName)   throws Exception {  Session session = sessionFactory.getCurrentSession();  StringBuffer hql = new StringBuffer("from HbUser where isDelete = 0

ORM进阶之Hibernate中对象的三大状态解析

ORM进阶之 ORM简单介绍 ORM进阶之Hibernate简单介绍及框架搭 ORM进阶之Hibernate的三大对象 ORM进阶之Hibernate中对象的三大状态解析 在Hibernatea中每一个对象都有三种状态,他们在这三种状态下,Hibernate会他们进行不同的处理.下边我们通过一张图来看一下这三种状态以及他们之间的互相转换! 能够看到对象可能会有这三种状态.暂时状态(transient),持久化状态(persistent).游离状态(detached).下边我们来分别来解释一下这三

分享知识-快乐自己:Hibernate 中Criteria Query查询详解

1):Hibernate 中Criteria Query查询详解 当查询数据时,人们往往需要设置查询条件.在SQL或HQL语句中,查询条件常常放在where子句中. 此外,Hibernate还支持Criteria查询(Criteria Query),这种查询方式把查询条件封装为一个Criteria对象. 在实际应用中,使用Session的createCriteria()方法构建一个org.hibernate.Criteria实例,然后把具体的查询条件通过Criteria的add()方法加入到Cr

使用SQLQuery 在Hibernate中使用sql语句

session.createSQLQuery.转载 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口.下面来描述如何使用这个API进行查询. 1.标量查询(Scalar queries) 最基本的SQL查询就是获得一个标量(数值)的列表. sess.createSQLQuery("SELECT * FROM CATS").list();sess.createSQLQuery("SELECT ID,

Hibernate中调用带有underscore的Column Name

Hibernate中默认的NamingStrategy不支持调用带有下划线的column name.在hibernate的bean中必须使用camel case.使用ImprovedNamingStrategy可以使hibernate成功map到带有下划线的column name.代码如下: 1. Configure文件 public static SessionFactory getSessionFactory() { if (sessionFactory == null) { Configu

详解Hibernate中的一级缓存

1.前言 在Hibernate中有三级缓存,本篇博客先详细的介绍一下,Hibernate中的一级缓存,也就是Session级别的缓存. 2.持久化对象 如果要说到Hibernate的缓存的话,那么首先咱得提一下hibernate中的持久化对象. 其中持久化对象有三种状态,分别是: transient(瞬时态):尚未与Session关联对象,失去引用的话,就会被JVM回收.一般就是直接New创建的对象. persistent(持久态):已经与当前session产生关联,并且相关联的session没