本文結合 MySQL 與 Spring 實務,系統梳理四大隔離等級行為差異、Spring 宣告式事務配置要點,並以實測數據量化降低隔離等級對效能的影響。
| 等級 | 髒讀 | 不可重複讀 | 幻讀 | 鎖特性 |
|---|---|---|---|---|
| READ UNCOMMITTED | ✅ | ✅ | ✅ | 無共享鎖,並發最高 |
| READ COMMITTED | ❌ | ✅ | ✅ | 讀取瞬間加共享鎖,讀完即釋放 |
| REPEATABLE READ (MySQL 預設) | ❌ | ❌ | ✅ (InnoDB Next-Key Lock 緩解) | 首次讀取加共享鎖至事務結束 |
| SERIALIZABLE | ❌ | ❌ | ❌ | 全表/範圍鎖,串行執行 |
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
關鍵陷阱:方法名必須符合模式(如 save*),若 Service 方法命名為 taskSave() 將不匹配,事務失效。建議統一命名規範或改用註解 @Transactional。
啟用 readOnly 時,Spring 會將該事務的隔離等級自動提升一級(READ COMMITTED → REPEATABLE READ),以確保同一事務內多次查詢結果一致。若資料庫預設已是 RR,則無額外影響。
場景:Task 模組首頁,同一事務內兩次查詢中間夾帶他人更新。
結果:含「同一事務多次查詢同一結果集」的複雜邏輯,降級至 RC 可明顯降低鎖持有時間、提升吞吐;單純單次查詢場景差異可忽略。
@Transactional。readOnly=true 優化唯讀事務,減少鎖爭用。Innodb_row_lock_waits、Innodb_row_lock_time_avg 持續調優。