1. 程式人生 > >通過query解析hibernate中的resultTransformer

通過query解析hibernate中的resultTransformer

從數據 查詢 tor resolve log 實現類 ces object als

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

通過query解析hibernate中的resultTransformer