首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 四大事務隔離級別深度解析與實戰演示

     編輯:MySQL 資料庫相關知識

標準隔離級別對比表

隔離級別髒讀不可重複讀幻讀備註
READ UNCOMMITTED✅ 可能✅ 可能✅ 可能最低級別,極少使用
READ COMMITTED❌ 不可能✅ 可能✅ 可能Oracle/PostgreSQL 默認
REPEATABLE READ❌ 不可能❌ 不可能✅ 可能InnoDB 默認
SERIALIZABLE❌ 不可能❌ 不可能❌ 不可能最高級別,串行執行,性能最差

核心概念定義

  • 髒讀:讀取到未提交事務的修改
  • 不可重複讀:同一事務內多次讀取同一行,結果不一致(被其他事務修改/刪除)
  • 幻讀:同一事務內多次按條件範圍查詢,結果集行數不一致(被其他事務插入/刪除)

配置與查看隔離級別

-- 全局永久生效(需重啟或 my.cnf)
SET GLOBAL transaction_isolation = 'REPEATABLE-READ';

-- 會話級臨時生效
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 下一個事務生效(默認行為)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 查看
SELECT @@global.transaction_isolation, @@session.transaction_isolation, @@transaction_isolation;

實戰演示:四大級別行為差異

準備工作:

CREATE TABLE t_test (id INT PRIMARY KEY, val VARCHAR(20)) ENGINE=InnoDB;
INSERT INTO t_test VALUES (1, 'a');

場景 1:髒讀

-- Session A
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT * FROM t_test; -- 空
UPDATE t_test SET val='dirty' WHERE id=1;
-- 不提交

-- Session B
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t_test; -- 讀到 val='dirty'(髒讀)
-- 其他級別讀不到

場景 2:不可重複讀

-- Session A
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT * FROM t_test WHERE id=1; -- val='a'

-- Session B
START TRANSACTION;
UPDATE t_test SET val='updated' WHERE id=1;
COMMIT;

-- Session A 再次查詢
SELECT * FROM t_test WHERE id=1; -- val='updated'(不可重複讀)
-- REPEATABLE READ 仍讀到 'a'

場景 3:可重複讀

-- Session A (默認 REPEATABLE READ)
START TRANSACTION;
SELECT * FROM t_test; -- 1 行

-- Session B
START TRANSACTION;
INSERT INTO t_test VALUES (2, 'b');
COMMIT;

-- Session A 再次查詢
SELECT * FROM t_test; -- 仍 1 行(可重複讀)
-- 提交後再查才看到 2 行

場景 4:幻讀

-- Session A
START TRANSACTION;
SELECT * FROM t_test WHERE id > 0; -- 1 行

-- Session B
START TRANSACTION;
INSERT INTO t_test VALUES (3, 'c');
COMMIT;

-- Session A 再次查詢
SELECT * FROM t_test WHERE id > 0; -- 仍 1 行(無幻讀?)
-- 但執行更新:
UPDATE t_test SET val='x' WHERE id > 0; -- 影響 2 行!(幻讀本質)
-- 或加鎖讀:
SELECT * FROM t_test WHERE id > 0 FOR UPDATE; -- 看到 2 行

InnoDB 如何解決幻讀?

Next-Key Locks(臨鍵鎖)

REPEATABLE READ + innodb_locks_unsafe_for_binlog=OFF(默認)下,範圍查詢自動加 Next-Key Lock(記錄鎖 + 間隙鎖),阻塞範圍內插入。

實驗驗證

-- Session A
START TRANSACTION;
SELECT * FROM t_test WHERE id <= 1 FOR UPDATE; -- 加鎖 id<=1 範圍

-- Session B
INSERT INTO t_test VALUES (2, 'd'); -- 成功(不在鎖範圍)
INSERT INTO t_test VALUES (0, 'e'); -- 阻塞(在鎖範圍 id<=1)

一致性讀 vs 鎖定讀

讀取方式SQL 示例可見性隔離級別影響
一致性讀SELECT ...事務啟動時快照REPEATABLE READ 固定快照
鎖定讀SELECT ... LOCK IN SHARE MODE
SELECT ... FOR UPDATE
最新提交版本讀到最新數據(提交讀語義)

生產環境選型建議

  1. 默認 REPEATABLE READ 滿足 95% 場景:InnoDB 通過 Next-Key Lock 實際上解決了大部分幻讀
  2. 高併發讀多寫少考慮 READ COMMITTED:減少間隙鎖衝突,需配合 binlog_format=ROW
  3. 嚴格金融對賬才用 SERIALIZABLE:性能代價極大,慎用
  4. 應用層控制:樂觀鎖、業務幂等設計比依賴數據庫隔離級別更靈活

總結

MySQL/InnoDB 以 REPEATABLE READ 為默認,通過 MVCC + Next-Key Lock 在性能與一致性間取得平衡。理解四大級別的語義邊界,結合 FOR UPDATE/LOCK IN SHARE MODE 顯式加鎖,是處理並發一致性問題的核心技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved