Hibernate 默認 autoCommit=false,手動控制事務代碼分散、易漏提交/回滾。Spring 提供 **聲明式事務管理**(AOP 切面),將事務邊界從業務代碼剝離,支持:
SessionFactory / EntityManagerFactory 無縫集成。<!-- 1. 事務管理器:綁定 Hibernate SessionFactory -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 2. 事務屬性定義(通過 tx:advice) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 增刪改:REQUIRED,拋運行時異常回滾 -->
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<!-- 查詢:只讀、不支持事務(性能優化) -->
<tx:method name="get*" propagation="NOT_SUPPORTED" read-only="true"/>
<tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true"/>
<tx:method name="query*" propagation="NOT_SUPPORTED" read-only="true"/>
<tx:method name="count*" propagation="NOT_SUPPORTED" read-only="true"/>
<!-- 其餘默認 -->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 3. AOP 切面:將事務應用到 Service 層 -->
<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 {
@Bean
public PlatformTransactionManager txManager(SessionFactory sf) {
return new HibernateTransactionManager(sf);
}
}
// Service 類
@Service
@Transactional(readOnly = true) // 類級別默認只讀
public class OrderService {
@Autowired OrderRepository repo;
@Transactional(readOnly = false, rollbackFor = Exception.class)
public Order createOrder(OrderDTO dto) { ... }
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendConfirmationEmail(Order order) { ... } // 獨立事務,不影響主訂單
}
| 常量 | 行為 | 典型場景 |
|---|---|---|
REQUIRED | 有事務加入,無則新建(默認) | 90% 業務方法 |
SUPPORTS | 有事務加入,無則非事務運行 | 查詢方法,允許在事務外調用 |
MANDATORY | 必須在現有事務中運行,否則拋異常 | 強制要求事務上下文的核心操作 |
REQUIRES_NEW | **掛起當前事務,新建獨立事務** | 日誌記錄、審計、發送通知,不回滾主業務 |
NOT_SUPPORTED | 掛起當前事務,以非事務方式運行 | 長耗時查詢、外部 API 調用,避免長事務持有連接 |
NEVER | 不允許事務,有則拋異常 | 嚴禁事務的工具方法 |
NESTED | 嵌套事務(保存點),外層回滾內層必回滾,內層回滾外層可繼續 | 批量處理中單條失敗回滾,其餘繼續(需 JDBC 3.0+ 驅動支持) |
| Spring 常量 | 資料庫級別 | 髒讀 | 不可重複讀 | 幻讀 | 性能 |
|---|---|---|---|---|---|
DEFAULT | 資料庫默認(通常 RC) | 視具體 DB | 視具體 DB | 視具體 DB | — |
READ_UNCOMMITTED | Read Uncommitted | ✅ | ✅ | ✅ | 最高 |
READ_COMMITTED | Read Committed (Oracle/PG 默認) | ❌ | ✅ | ✅ | 高 |
REPEATABLE_READ | Repeatable Read (MySQL 默認) | ❌ | ❌ | ✅ (MySQL 靠 Gap Lock 解決) | 中 |
SERIALIZABLE | Serializable | ❌ | ❌ | ❌ | 最低 |
**建議**:大多數互聯網業務用 **READ_COMMITTED** + **樂觀鎖(@Version)** 解決併發衝突,兼顧性能與正確性。
RuntimeException 及子類、Error)觸發回滾。rollbackFor = Exception.class:所有受檢異常也回滾(常用)。noRollbackFor = BusinessException.class:業務異常不回滾(如庫存不足屬業務流程,不應回滾)。TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。事務邊界決定了 **Session 生命周期**(默認 OpenSessionInView 會延長到視圖渲染)。若事務在 Service 層結束,Session 關閉,二級緩存才真正生效(寫入/失效)。**將事務配置在 Service 層而非 DAO 層**,既保證業務原子性,又讓二級緩存正常工作。
rollbackFor、try-catch 吞掉異常未重拋。REQUIRES_NEW 縮短鎖持有時間。Spring 聲明式事務通過 AOP 將「何時開啟、何時提交、何時回滾、隔離級別、傳播行為」集中配置。掌握 **傳播行為七大類、隔離級別四大類、回滾規則精準控制**,並遵循 **「事務在 Service 層、查詢走只讀、寫操作配回滾、長任務拆獨立事務」** 原則,即可構建健壯、高性能的數據訪問層。