MySQL 事务隔离与锁的测试

  • 最新使用 MySQL 8.0.29 测试

修改事务隔离级别

  • 注:Windows 上的测试最好用自带的 mysql.exe 客户端
    • 不要用 GUI,GUI 可能会使语句单独执行
    • 使用 BEGIN;COMMIT; 就可以测试
  • 改变全局事务隔离级别时,当前 session 需退出重进才有效
    • 设置 SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    • 级别 {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
  • 改当前级别 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;;要加 SESSION 关键字,否则不生效
  • 查看当前级别 SHOW VARIABLES LIKE 'transaction_isolation';

表创建

CREATE TABLE `test` (
 `id` INT NOT NULL, 
 `age` INT DEFAULT NULL, 
 `enname` VARCHAR(255) DEFAULT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;

顺序读

  1. Next-Key 锁 实现

  2. T1 先执行读,给相关区间加读锁;后续的事务可以读,但 CUD 的时候会被阻塞

T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
SELECT * FROM test WHERE id <= 5; // 锁 (-∞, 5]--
C: INSERT INTO test VALUES(6, 35, 'c'); // 成功-
C: INSERT INTO test VALUES(4, 25, 'c'); // 阻塞-
U: UPDATE test SET enname = 'a' WHERE id = 8; // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 阻塞-
D: DELETE FROM test WHERE id = 8; // 成功-
D: DELETE FROM test WHERE id = 5; // 阻塞-
T: COMMIT; // 提交数据-
SELECT * FROM test WHERE id <= 5; // 不存在幻读--
  1. T1 先执行 CUD,给相关区间加写锁;后续的事务 CRUD 的时候都会被阻塞
T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
UPDATE test SET enname = 'a' WHERE id <= 5; // 锁 (-∞, 5]--
R: SELECT * FROM test WHERE id > 5; // 成功-
R: SELECT * FROM test WHERE id >= 5; // 阻塞-
C: INSERT INTO test VALUES(6, 35, 'c'); // 成功-
C: INSERT INTO test VALUES(4, 25, 'c'); // 阻塞-
U: UPDATE test SET enname = 'a' WHERE id = 8; // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 阻塞-
D: DELETE FROM test WHERE id = 8; // 成功-
D: DELETE FROM test WHERE id = 5; // 阻塞-

可重复读

  1. Next-Key 锁 实现

  2. T1 先执行读,并没有给相关区间加读锁,只是生成快照;后续的事务可以 CRUD,并不会被阻塞

T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
SELECT * FROM test WHERE id <= 5; // 不加锁--
C: INSERT INTO test VALUES(4, 15, 'c'); // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 成功-
D: DELETE FROM test WHERE id = 5; // 成功-
T: COMMIT; // 提交数据-
SELECT * FROM test WHERE id <= 5; // 不存在幻读--
  1. T1 先执行 CUR,给相关区间加写锁;后续的事务 CUD 的时候都会被阻塞,但读不加锁
T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
UPDATE test SET enname = 'a' WHERE id <= 5; // 锁 (-∞, 5]--
R: SELECT * FROM test; // 成功-
C: INSERT INTO test VALUES(6, 35, 'c'); // 成功-
C: INSERT INTO test VALUES(4, 25, 'c'); // 阻塞-
U: UPDATE test SET enname='a' WHERE id = 8; // 成功-
U: UPDATE test SET enname='a' WHERE id = 5; // 阻塞-
D: DELETE FROM test WHERE id = 8; // 成功-
D: DELETE FROM test WHERE id = 5; // 阻塞-

提交读

  1. 记录锁实现

  2. T1 先执行读,并不会给相关记录加读锁;后续的事务可以 CRUD,并不会被阻塞

T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
SELECT * FROM test WHERE id <= 5; // 不加锁--
C: INSERT INTO test VALUES(4, 15, 'c'); // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 成功-
D: DELETE FROM test WHERE id = 5; // 成功-
T: COMMIT; // 提交数据-
SELECT * FROM test WHERE id <= 5; // 存在不可重复读、幻读--
  1. T1 先执行 CUR,给相关行记录加写锁;后续的事务 CUD 的时候都会被阻塞,但读不加锁
T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
UPDATE test SET enname = 'a' WHERE id <= 5; // 锁第1行和第5行记录--
R: SELECT * FROM test; // 成功-
C: INSERT INTO test VALUES(4, 15, 'c'); // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 8; // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 阻塞-
D: DELETE FROM test WHERE id = 8; // 成功-
D: DELETE FROM test WHERE id = 5; // 阻塞-

未提交读

  1. 记录锁实现

  2. T1 先执行读,并不会给相关记录加读锁;后续的事务可以 CRUD,并不会被阻塞

T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
SELECT * FROM test WHERE id <= 5; // 不加锁--
C: INSERT INTO test VALUES(4, 15, 'c'); // 成功-
SELECT * FROM test WHERE id <= 5; // 存在幻读--
U: UPDATE test SET enname = 'a' WHERE id = 5; // 成功-
D: DELETE FROM test WHERE id = 5; // 成功-
T: -- COMMIT; // 不提交数据-
SELECT * FROM test WHERE id <= 5; // 存在脏读、不重复读、幻读--
  1. T1 先执行 CUR,给相关行记录加写锁;后续的事务 CUD 的时候都会被阻塞,但读不加锁
T1T2Main
-SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-TRUNCATE TABLE test;
-INSERT INTO test VALUES(1, 10, 'a'), (5, 20, 'b'), (8, 30, 'c'), (10, 40, 'd');
START TRANSACTION;START TRANSACTION;-
UPDATE test SET enname = 'a' WHERE id <= 5; // 锁第1行和第5行记录--
R: SELECT * FROM test; // 成功-
C: INSERT INTO test VALUES(4, 15, 'c'); // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 8; // 成功-
U: UPDATE test SET enname = 'a' WHERE id = 5; // 阻塞-
D: DELETE FROM test WHERE id = 8; // 成功-
D: DELETE FROM test WHERE id = 5; // 阻塞-

总结

隔离级别RW - 先读RW - 后 CUR]WR - 先 CURWR - 后读
顺序读给区间加 Next-Key 读锁读任意执行,CUD 阻塞给区间加 Next-Key 写锁CURD 都阻塞
可重复读不加锁任意执行加 Next-Key 锁读任意执行,CUD 阻塞
提交读不加锁任意执行给行加写锁(记录锁)读任意执行,CUD 阻塞
未提交读不加锁任意执行给行加写锁(记录锁)读任意执行,CUD 阻塞

注:

  1. 如果是id = 5的操作,只是用行锁
  2. 不同隔离级别之间也是按锁规则执行(如 T1 顺序读,T2 未提交读)
  3. MySQL 默认是隐式添加事务操作,即 T1 事务开启未释放锁,用户 T2 未开启事务时的操作也会阻塞

非索引列上操作

  • 示例:
T1:
  UPDATE test SET enname = 'a' WHERE age <= 10;
T2: 
  INSERT INTO test VALUES(9, 11, 'c'); -- 检验 Next-Key 锁
  INSERT INTO test VALUES(9, 41, 'c'); -- 检验表锁
  UPDATE test SET enname = 'a' WHERE age > 20; -- 检验表锁
  UPDATE test SET enname = 'a' WHERE age < 20; -- 检验行锁
级别锁情况
顺序读锁表
可重复读锁表
提交读锁行
未提交读锁行

  • 锁表说明:没索引,不好计算 Next-Key,因此锁表
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值