Spring 4.1.4 整合 Hibernate 4 時,發現未聲明 @Transactional、未配置 AOP 事務切面,直接呼叫 session.save() 竟能成功提交資料庫?本文深入剖析 Hibernate 原生事務、Spring 事務代理、CurrentSessionContext 三者交互機制。
// 無 @Transactional、無 XML 事務配置
Session session = sessionFactory.getCurrentSession();
session.save(entity); // 竟然提交成功!
| 層面 | Hibernate 原生 | Spring 事務管理 |
|---|---|---|
| API | Transaction tx = session.beginTransaction(); tx.commit(); | @Transactional / XML <tx:advice> |
| 邊界 | 手動控制(程式碼侵入) | 聲明式、切面攔截(非侵入) |
| 回滾 | 手動 tx.rollback() | 異常自動回滾、支援嵌套 |
| 傳播行為 | 無 | REQUIRED、REQUIRES_NEW 等 7 種 |
sessionFactory.getCurrentSession() 依賴 hibernate.current_session_context_class 設定(如 thread、managed),從當前執行緒取得 Session。autoCommit=true,且未開啟 Hibernate 事務,每條 SQL 即時提交。getCurrentSession() 在 SessionFactory 關閉或手動 close() 時自動 flush 並提交(視實作而定)。// 業務邏輯:轉帳(扣款 + 入帳)
public void transfer(Account from, Account to, int amount) {
session.update(from); // 扣款成功
// 這裡拋出異常(如網路中斷)
session.update(to); // 入帳失敗
// 結果:資料不一致,扣款已提交無法回滾!
}
無 Spring 事務邊界 = 無原子性保障。多步操作若中途失敗,已執行步驟無法回滾,導致髒資料。
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>
@Configuration
@EnableTransactionManagement
public class TxConfig { ... }
@Service
public class AccountService {
@Transactional(rollbackFor = Exception.class)
public void transfer(...) { ... }
}
HibernateTemplate,直接注入 SessionFactory 呼叫 getCurrentSession() 即可。HibernateTemplate 主要解決舊版 Hibernate checked exception、Session 管理樣板碼,現代版本已無此痛點。HibernateTemplate.save() 報「事務為只讀」,檢查 @Transactional(readOnly=true) 或 XML read-only="true" 配置錯誤。「能存進去」≠「事務正確」。Hibernate 原生事務僅提供單操作提交,Spring 事務管理才是業務級原子性、一致性、隔離性的守護者。務必在 Service 層配置聲明式事務,切勿僥倖依賴自動提交行為。