獲得hibernate的sql語句
我們知道hibernate會將hql解析成sql,也許在某些時候,我們需要這些sql。
不過hibernate的介面中沒有公開的api,看來我們得自己行動了。
1.開始前的工作
1.1 知道如何閱讀javadoc api
1.2 知道如何使用ant編譯hibernate源碼包
1.3 hibernate源碼包在hibernate壓縮包的src目錄,api文檔在doc目錄
2.在執行Query.list()方法時,hibernate在控制台輸出sql。從api文檔中我們知道, Query介面有個實作類別是net.sf.hibernate.impl.AbstractQueryImpl,但這個虛類中並沒有實現list方法,繼續查該類的子類net.sf.hibernate.impl.QueryImpl,呵呵,找到了。
listpublic List list() throws HibernateException
-
Description copied from interface:
Query
-
Return the query results as a List. If the query contains multiple results pre row, the results are returned in an instance of Object[].
-
-
Returns:
-
the result list
-
Throws:
-
HibernateException
|
3.查看net.sf.hibernate.impl.QueryImpl原始碼,發現這裡吧實現丟給了Session介面,看來我們得去找Session介面的麻煩。
public List list() throws HibernateException { verifyParameters(); Map namedParams = getNamedParams(); return getSession().find( bindParameterLists(namedParams), getQueryParameters(namedParams) ); } |
4.介面是沒有實現代碼的,因此我們直接看實作類別net.sf.hibernate.impl.SessionImple的原始碼
| public List find(String query, QueryParameters queryParameters) throws HibernateException { if ( log.isTraceEnabled() ) { log.trace( "find: " + query ); queryParameters.traceParameters(factory); } queryParameters.validateParameters(); QueryTranslator[] q = getQueries(query, false); List results = Collections.EMPTY_LIST; dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called //execute the queries and return all result lists as a single list try { for ( int i=0; i<q.length; i++ ) { List currentResults; try { currentResults = q[i].list(this, queryParameters); // 原來list是由這個類做的 } catch (SQLException sqle) { throw new JDBCException("Could not execute query", sqle); } currentResults.addAll(results); results = currentResults; } } finally { dontFlushFromFind--; } return results; } |
5. 在api文檔左下角All Classes架構搜尋QueryTranslator,查到後點擊查看api,嗯,有料。
getSQLStringpublic String getSQLString()
-
Description copied from class:
Loader
-
The SQL query string to be called; implemented by all subclasses
-
-
Specified by:
-
getSQLString in class
Loader
|
6.但是我們並不想處理第4步中找到的find方法的QueryParameters參數,怎麼辦捏?參考一下其他find方法
private static final Object[] NO_ARGS = ArrayHelper.EMPTY_STRING_ARRAY; private static final Type[] NO_TYPES = ArrayHelper.EMPTY_TYPE_ARRAY;/** * Retrieve a list of persistent objects using a hibernate query */ public List find(String query) throws HibernateException { return find(query, NO_ARGS, NO_TYPES); // 他交給了三個參數的介面 } public List find(String query, Object value, Type type) throws HibernateException { return find( query, new Object[] { value }, new Type[] { type } ); // 又丟給另一個介面處理 } public List find(String query, Object[] values, Type[] types) throws HibernateException { return find(query, new QueryParameters(types, values) ); // 回到2參數的介面手裡了 } |
7.開始修改,將第4步找到的代碼複製出來更改如下,然後添加回SessionImpl類
| public String[] getSQLStrings(String query) throws HibernateException { // 採用單參數介面處理queryParameters的方法 QueryParameters queryParameters = new QueryParameters(NO_ARGS, NO_TYPES); if ( log.isTraceEnabled() ) { log.trace( "find: " + query ); queryParameters.traceParameters(factory); } queryParameters.validateParameters(); QueryTranslator[] q = getQueries(query, false); String[] results = new String[q.length]; // 建立傳回值 dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called //execute the queries and return all result lists as a single list try { for ( int i=0; i<q.length; i++ ) { try { results[i] = q[i].getSQLString(); // 獲得sql語句 } catch (SQLException sqle) { throw new JDBCException("Could not execute query", sqle); } } } finally { dontFlushFromFind--; } return results; } |
8.給Session介面增加一個方法
| public String[] getSQLStrings(String query) throws HibernateException; |
9.編譯之後大功告成,我們可以使用Session.getSQLStrings(query)獲得sql語句數組