企業級應用常混合使用 ORM(Hibernate/JPA)與 JDBC(Spring JDBC/iBatis)框架。Spring 的智能事務管理機制允許僅配置 ORM 對應的事務管理器(如 HibernateTransactionManager),即可實現多框架共用同一資料庫連線與事務上下文。
Hibernate Session 內部封裝了 JDBC Connection。HibernateTransactionManager 開啟事務時,會將該 Connection 綁定至線程上下文,JdbcTemplate 透過 DataSourceUtils 即可感知並復用此連線。日誌清晰顯示:Hibernate 開啟 Session → 準備 JDBC Connection → JdbcTemplate 執行 SQL 時 Participating in existing transaction → 統一提交。
場景: 同一事務中先用 Hibernate 更新實體(處於一級快取),再用 JDBC 直接更新同一資料表。
問題: Hibernate 預設在事務提交時才 flush 快取。JDBC 先寫入資料庫,隨後 Hibernate 提交時將快取中的舊狀態覆蓋資料庫,導致 JDBC 更新丟失。
解決: 在 Hibernate 操作後顯式調用 hibernateTemplate.flush(),強制同步快取至資料庫,再執行 JDBC 操作。或調整業務邏輯順序:優先 JDBC 寫入,再 Hibernate 讀取/修改。
flush(),並同步維護 Hibernate 快取狀態。Spring AOP 基於動態代理(JDK Proxy 或 CGLib),無法攔截特定修飾符的方法,導致事務增強失效:
| 代理模式 | 無法增強的方法 |
|---|---|
| JDK 動態代理(介面) | 非 public 方法;public static 方法 |
| CGLib 字節碼代理(類) | private、final、static 方法 |
定義含 private、final、static、public 四種方法的 Service,啟用 proxy-target-class="true"(CGLib)。運行日誌顯示:前三者無事務日誌輸出,僅 public 方法觸發事務創建、提交。
無法被 AOP 增強的方法,不能主動開啟新事務,但可參與外層傳播的事務。若被事務方法調用,共享外層連線與事務上下文;若由非事務方法調用,則無事務環境。風險點: public static/public final 方法常被 Web 層直接調用,若調用者無事務,則隱性運行在無事務模式下。
混合持久化技術時:用 ORM 事務管理器統一協調,警惕快取同步問題。AOP 代理時:避免在 Service 公共 API 使用 final/static,核心業務邏輯保持 public 非 final。下篇將聚焦連線洩漏完整解決方案。