任何包装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