Hibernate 將 HQL 轉換為 SQL 並在執行時輸出至控制台(開啟 show_sql 時),但 API 未提供直接獲取 SQL 字串的方法。本文演示如何深入 Hibernate 2.1.6 源碼,擴展 Session 接口新增 getSQLStrings(String query) 方法,使應用程式能程式化取得即將執行的 SQL 語句陣列,適用於日誌審計、效能分析、動態報表等場景。
Session.find()。QueryTranslator 將 HQL 編譯為 SQL。Hibernate 內部提供多個 find 重載,最終委派至 find(String, QueryParameters)。關鍵在於構建空的 QueryParameters(NO_ARGS, NO_TYPES)以避免參數綁定邏輯。
public String[] getSQLStrings(String query) throws HibernateException {
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++;
try {
for (int i = 0; i < q.length; i++) {
results[i] = q[i].getSQLString(); // 核心:取得 SQL 字串
}
} catch (SQLException sqle) {
throw new HibernateException("Could not execute query", sqle);
} finally {
dontFlushFromFind--;
}
return results;
}
public String[] getSQLStrings(String query) throws HibernateException;
需具備:閱讀 Javadoc 能力、Ant 建置環境、Hibernate 源碼包(src/ 目錄)。編譯後將產出的類別檔打包替換專案依賴的 hibernate.jar。
Session session = sessionFactory.openSession();
String hql = "from User u where u.name = ?";
String[] sqls = session.getSQLStrings(hql);
for (String sql : sqls) {
System.out.println("Generated SQL: " + sql);
// 輸出範例:select user0_.id as id0_, user0_.name as name0_ from User user0_ where user0_.name=?
}
session.close();
Interceptor、StatementInspector 或 hibernate.generate_statistics 等官方機制。?,實際參數值需另行獲取。透過閱讀源碼理解 Hibernate 內部查詢翻譯流程,不僅能解決「獲取 SQL」需求,更能深化對 ORM 框架運作機制的掌握。現代版本請優先使用官方標準 API。