MySQL 事務隔離級別深度解析:從讀未提交到序列化
事務隔離級別定義了不同事務之間的可見性與影響範圍,是資料庫並發控制的核心。MySQL(InnoDB)支援四種標準隔離級別,由低到高依次為:
1. Read Uncommitted(讀未提交)
- 事務 A 可讀取事務 B 已修改但未提交 的數據。
- 現象:髒讀。
- 性能最好,但數據一致性最差,生產環境極少使用。
2. Read Committed(讀已提交)
- 事務 A 僅能讀取事務 B 已提交 的數據。
- 每次
SELECT 都會生成新的數據快照,因此同一事務多次查詢結果可能不同。
- 現象:不可重複讀。
- Oracle 等多數關係型資料庫的預設級別。
3. Repeatable Read(可重複讀)— MySQL InnoDB 預設
- 事務 A 僅能讀取事務 B 已提交的數據,且同一事務內每次讀取結果完全相同。
- 原因:事務讀取的是事務開始時的數據快照,該快照在事務結束前保持不變。
- 幻讀問題仍存在:若不同事務修改未提交的數據存在主鍵/唯一鍵衝突,後執行的事務會被掛起;即使先執行事務回滾,後者也讀不到先前插入的衝突行,彷彿「幻影」般存在卻不可見。
- 案例: 表 T 有唯一鍵 UK。事務 A 插入 UK=x 未提交;事務 B 插入 UK=x 被掛起。A 提交 → B 報唯一鍵錯誤;A 刪除 UK=x 後提交 → B 插入成功,但 B 提交前始終
SELECT 不到 A 插入的行。
4. Serializable(序列化)
- 事務必須串行執行,完全隔離,犧牲並發性換取最高一致性。
- 通過鎖機制實現,性能開銷最大。
隔離級別演進邏輯總結
隔離級別針對事務的 SELECT 操作,按隔離程度逐步加強:
- 不隔離(髒讀)
- 不可重複讀
- 可重複讀但存在幻讀
- 完全串行化(禁用並發,解決幻讀)
關於幻讀的常見誤區澄清
- 錯誤觀點:「InnoDB 通過 MVCC 在 RR 級已解決幻讀」。
事實:MVCC 採用類樂觀鎖機制,原理上無法解決幻讀。上述案例證實 RR 級下幻讀依然存在。
- 模糊描述:「事務 A 讀取一定範圍後,事務 B 插入數據,A 更新時『驚奇』發現」。
精確定義:事務 A SELECT 不到 事務 B 更新的數據,但這些數據卻影響 A 的操作(如唯一鍵衝突),如同「幻影」——看不見它,但它已經存在。
記憶口訣
- 讀未提交:不管其他事務是否提交,都能讀到它們的數據。
- 讀已提交:只有其他事務提交後,才能讀到它們的數據。
- 可重複讀:只有自己提交後,才能讀到其他事務提交的數據。
- 序列化:事務逐個執行,當前事務提交前,其他全掛起。
建議: 大多數業務採用預設 Repeatable Read 即可;若極度敏感於幻讀(如嚴格計費、庫存扣減),可在應用層加鎖或升級至 Serializable,並配合行級鎖優化並發。