資料庫隔離級別直接影響並發效能與資料一致性,Spring 事務配置進一步封裝隔離行為。本文以 MySQL 為例,解析四大隔離級別特性、Spring 宣告式事務配置要點、readOnly 屬性對隔離級別的隱含影響,並實測隔離級別調整對特定業務場景的效能差異。
autocommit=1)。PROPAGATION_REQUIRED (預設,支援巢狀)、PROPAGATION_REQUIRES_NEW (掛起當前開新)、PROPAGATION_NESTED (巢狀保存點) 等。| 隔離級別 | 常數 | 髒讀 | 不可重複讀 | 幻讀 | 鎖機制 | 適用場景 |
|---|---|---|---|---|---|---|
| 讀未提交 | READ UNCOMMITTED | ✓ | ✓ | ✓ | 無共享鎖 | 極少用,統計近似值 |
| 讀已提交 | READ COMMITTED | ✗ | ✓ | ✓ | 行鎖 (釋放快) | Oracle/SQL Server 預設,高併發 OLTP |
| 可重複讀 | REPEATABLE READ | ✗ | ✗ | ✓ (間隙鎖緩解) | 行鎖+間隙鎖 (Next-Key Lock) | MySQL InnoDB 預設,一致性要求高 |
| 序列化 | SERIALIZABLE | ✗ | ✗ | ✗ | 表鎖/範圍鎖 | 極嚴格一致性,效能極差 |
關鍵差異:
LOCK IN SHARE MODE/FOR UPDATE) 才加鎖。<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" 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:method name="*" propagation="REQUIRED" />
</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>
@Service
@Transactional(readOnly = true) // 類級別預設唯讀
public class UserService {
@Transactional(readOnly = false) // 覆蓋類級別
public void saveUser(User u) { ... }
public User getUser(Long id) { ... } // 繼承類級別 readOnly=true
}
save*、update* 等前綴的方法生效,taskSave() 不會觸發事務,建議統一命名規範或改用註解。@Transactional(isolation = Isolation.REPEATABLE_READ) 顯式指定,與 readOnly 無關。RuntimeException、Error,受檢異常需 rollbackFor = Exception.class。本地 MySQL,同一事務內用戶 A 兩次查詢,間隙用戶 B 修改記錄。
| 隔離級別 | 用戶 A 兩次查詢結果 | 鎖行為 | 平均響應時間 (任務首頁) |
|---|---|---|---|
| REPEATABLE READ (預設) | 不一致 (第二次見到 B 的修改) | 快照讀無鎖,當前讀加 Next-Key Lock | 基準值 |
| READ COMMITTED | 一致 (第二次未見 B 修改,因行鎖阻塞) | 讀取加行共享鎖,釋放快 | 提升 15-20% (特定邏輯) |

| 隔離級別 | 共享鎖 (S) | 排他鎖 (X) | 間隙鎖 (GAP) | Next-Key Lock |
|---|---|---|---|---|
| READ UNCOMMITTED | 不加 | 加 | 不加 | 不加 |
| READ COMMITTED | 不加 (快照讀) | 加 | 不加 | 不加 |
| REPEATABLE READ | 加 (當前讀) | 加 | 加 | 加 (當前讀) |
| SERIALIZABLE | 加 (全表/範圍) | 加 | 加 | 加 |
實務判斷鎖類型口訣:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED + innodb_locks_unsafe_for_binlog=1 (5.6+ 已廢棄,改用 binlog_format=ROW 避免 GAP 鎖)。@Transactional(readOnly=true),寫方法覆蓋 readOnly=false,顯式指定 isolation 僅在極少數場景。Innodb_row_lock_waits、Innodb_row_lock_time_avg、Innodb_deadlocks,鎖等待上升時優先優化 SQL/索引,而非降級隔離級別。隔離級別調優是「最後手段」,索引優化、SQL 重寫、架構拆分才是正道。理解鎖與 MVCC 底層機制,方能在關鍵時刻做出正確權衡。