| 隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | 備註 |
|---|---|---|---|---|
| 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');
-- 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'(髒讀) -- 其他級別讀不到
-- 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'
-- 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 行
-- 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 行
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)
| 讀取方式 | SQL 示例 | 可見性 | 隔離級別影響 |
|---|---|---|---|
| 一致性讀 | SELECT ... | 事務啟動時快照 | REPEATABLE READ 固定快照 |
| 鎖定讀 | SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE | 最新提交版本 | 讀到最新數據(提交讀語義) |
binlog_format=ROWMySQL/InnoDB 以 REPEATABLE READ 為默認,通過 MVCC + Next-Key Lock 在性能與一致性間取得平衡。理解四大級別的語義邊界,結合 FOR UPDATE/LOCK IN SHARE MODE 顯式加鎖,是處理並發一致性問題的核心技能。