通过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

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注