通過query解析hibernate中的resultTransformer
任何包裝jdbc的框架,都離不開將最終的數據封裝成java對象的一個過程。在jdbc中,取得的數據被封裝在resultset中,通過叠代resultset來一次次的取得相應的字段和數據值。數據庫框架始終需要解決的問題在於將resultset中的字段名稱信息和相應的字段值對應起來,然後封裝成對象,最後將所有的對象形成一個集合,並最終返回給調用者。 任何數據庫框架都逃不過這中間的處理邏輯,只不過如何將這些邏輯分散在上下的處理中。在Hibernate中,同樣也有類似的東西,這個接口就叫做ResultTransformer。
Transformer的定義如下:
public interfaceResultTransformer 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