Connection Management and Monitoring#
本章延續 JDBC Connection Management 的概念,說明 Hibernate 的 connection provider 機制,以及如何監控 SQL statement 的執行。由於 JPA provider 會代替開發者產生 SQL,因此監控這些 statement 的行為與效能變得格外重要。
JPA Connection Management#
- JPA 1.0 的設計高度依賴 Java EE application server,所有 database connection 由 application server 管理,提供 connection pooling、monitoring 與 JTA 功能
- 在 Java EE 環境中,
DataSource透過 JNDI 定位,開發者需在persistence.xml中指定 JNDI 名稱 - JTA transaction 使用
jta-data-source,RESOURCE_LOCAL transaction 使用non-jta-data-source - 獨立應用程式(stand-alone)通常透過 dependency injection 設定
DataSource,而非 JNDI
自 JPA 2.0 起,標準化了以下連線設定屬性:
javax.persistence.jdbc.driver– Driver class namejavax.persistence.jdbc.url– 連線 URLjavax.persistence.jdbc.user– 使用者名稱javax.persistence.jdbc.password– 密碼
這些屬性本身不足以滿足企業應用的需求,connection pooling 和 monitoring 仍屬於 JPA 實作層級的議題,需要依靠 Hibernate 的 connection provider 機制。
Hibernate Connection Providers#
Hibernate 定義了 ConnectionProvider 介面(org.hibernate.engine.jdbc.connections.spi.ConnectionProvider)作為連線工廠的抽象,支援 JDBC Driver 連線、RESOURCE_LOCAL 以及 JTA DataSource 等多種組態方式。
DriverManagerConnectionProvider#
- 當設定 JPA 2.0 標準屬性或 Hibernate 專屬屬性(如
hibernate.connection.driver_class、hibernate.connection.url等)時,Hibernate 會選用此 provider - 雖然透過
DriverManager取得連線並使用簡易的 pooling 實作來減少開銷,但 Hibernate 官方不建議在 production 環境使用此 provider
C3P0ConnectionProvider#
- C3P0 是成熟的 connection pooling 方案,只需設定至少一個
hibernate.c3p0前綴的屬性即可啟用 - C3P0(2001)與 Apache DBCP(2002)是最早期且廣泛部署的 Java connection pool
- 後來 BoneCP(2010)出現,但目前已被 HikariCP 取代
HikariCPConnectionProvider#
- HikariCP 是目前最快的 connection pool 之一,Hibernate 5 透過
hibernate-hikaricpdependency 原生支援 - 透過設定
hibernate.connection.provider_class為org.hibernate.hikaricp.internal.HikariCPConnectionProvider啟用 - 使用專屬的
hibernate.hikari.*屬性進行設定(如dataSourceClassName、dataSource.url、maximumPoolSize等)
DatasourceConnectionProvider#
- 當 JPA 設定檔中定義
non-jta-data-source或jta-data-source,或指定hibernate.connection.datasource時,選用此 provider - 相容於 JTA transaction(Java EE 環境中的必要條件)
- 與 Spring 的 stand-alone JTA transaction manager(如 Bitronix、Atomikos)及 Java EE
DataSource(s)皆相容
即使使用 HikariCP,
DatasourceConnectionProvider仍是首選,因為外部設定DataSource提供了更大的彈性,可方便地加入 connection pooling、monitoring 與 logging 等裝飾功能。
Connection Release Modes#
Hibernate 延遲取得 database connection,直到當前 transaction 執行第一個 SQL statement 時才從 pool 取得連線。連線釋放策略透過 hibernate.connection.release_mode 設定:
after_transaction– 連線在 transaction commit 或 rollback 後才釋放after_statement– 每次 statement 執行完畢後釋放連線,下次執行前重新取得。此策略是為了避免 application server 誤判 EJB 呼叫之間的 connection leakauto(預設值)– RESOURCE_LOCAL 使用after_transaction,JTA 使用after_statement
after_statement模式因頻繁的 connection 取得/釋放循環,會產生明顯的效能損耗。測試顯示 statement 數量越多,after_statement與after_transaction的差距越大。若 JTA transaction management 不會干擾連線釋放策略,建議改用after_transaction以獲得更好的效能。

Figure 8.1: Connection release mode
Monitoring Connections#
使用外部設定的 DataSource 是推薦做法,因為可以透過 proxy 模式裝飾 DataSource,加入 connection pooling、monitoring 與 logging 功能。FlexyPool 就是採用此架構,透過 proxy 攔截 connection 的取得與釋放請求來監控使用情況。

Figure 8.2: FlexyPool architecture
Hibernate Statistics#
- Hibernate 內建 statistics collector,可蒐集 database connection、
Sessiontransaction 和 second-level cache 使用的相關通知 StatisticsImplementor介面定義了各種 Hibernate 內部事件的攔截契約(如openSession、flush、connect、prepareStatement、endTransaction等)- 預設停用,需設定
hibernate.generate_statistics為true啟用 - 搭配 logger 設定(
org.hibernate.engine.internal.StatisticalLoggingSessionEventListener設為info),每次Session結束時會輸出效能報告

Figure 8.3: Hibernate StatisticsImplementor interface
Customizing Statistics#
- 預設的 statistics collector 僅計算 callback 呼叫次數,開發者可自訂
StatisticsImplementor實作 - 可透過繼承
ConcurrentStatisticsImpl並覆寫connect和endTransaction方法,加入自訂指標 - 透過
StatisticsFactory介面與hibernate.stats.factory設定屬性註冊自訂實作 - 建議使用成熟的 metrics 框架(如 Dropwizard Metrics),支援 reservoir sampling、多種 reporter(SLF4J、JMX、Ganglia、Graphite)等功能
對於高效能的 data access layer,statistics 和 metrics 是必要條件。Hibernate statistics 機制讓開發團隊能深入了解 Hibernate 的內部運作。
Statement Logging#
ORM 工具會自動產生 DML statement,開發者有責任驗證這些 statement 的正確性與效能影響。SQL statement logging 應從開發初期就啟用。
實作業務邏輯時,Definition of Done 應包含對所有相關 data access 操作的審查。及早遵循此規則,可在部署到 production 時省去大量問題排查。
Hibernate 提供以下 SQL logging 設定屬性:
hibernate.show_sql– 將 SQL 印到 console(應避免使用,改用 logging framework)hibernate.format_sql– 格式化 SQL statement 以提升可讀性hibernate.use_sql_comments– 在自動產生的 SQL 中加入註解
透過 logger 設定 org.hibernate.SQL 為 debug 層級,可啟用 statement logging。由於 Hibernate 使用 PreparedStatement,log 中的 bind parameter 會顯示為 ? 佔位符。
Statement Formatting#
- 設定
hibernate.format_sql為true可將 SQL 格式化為多行可讀格式 - 僅適用於開發階段,production 環境的 log 通常需要集中解析與彙整,多行格式會影響 log parsing
- 此設定僅影響 logged statement,實際送往 JDBC
Driver的 SQL 仍為單行文字 - 透過外部
DataSourceproxy 記錄的 statement 不受此設定影響
Statement-level Comments#
- 設定
hibernate.use_sql_comments為true,Hibernate 會在 SQL 中附加說明性註解 - 有助於理解:觸發 statement 的 entity state transition、選擇 join 的原因、使用的 locking 機制
- 與 formatting 不同,SQL comments 會傳播到底層 JDBC
Driver,因此在 production 環境建議停用以減少網路開銷
Logging Parameters#
由於 PreparedStatement 的 bind parameter 不會出現在 log 中,需要透過 proxy JDBC Driver 或 DataSource 來攔截 statement 執行並記錄實際參數值。
DataSource-proxy#
- 提供自訂 JDBC statement execution listener 的支援
- 採用程式化設定,適合 Spring 應用程式的 Java-based configuration
- 可記錄 batch insert 的完整參數,並將同批次的 statement 群組顯示
- 支援自訂 statement listener,可用於建構 query count validator,在開發階段防止 N+1 query 問題
datasource-proxy 的 custom statement listener 機制可用來建構 query count validator,在開發階段即時偵測並預防 N+1 query 問題。

Figure 8.4: DataSource-Proxy Architecture
P6Spy#
- 2002 年發布,支援 declarative configuration(透過
spy.properties檔案) - 可同時 proxy JDBC
Driver(適合 Java EE)和 JDBCDataSource(適合 Spring) - 輸出包含:Timestamp、Execution time、Category、Connection ID、Original statement、Formatted statement(含實際 bind values)
- 提供
outagedetection設定,可偵測 long-running statements
