MySQL行锁、表锁、间隙锁详解学习
环境准备
创建表
CREATE DATABASE TEST_INNODB;
use TEST_INNODB;
create table TEST_INNODB_LOCK(
a INT(11) primary key ,
b VARCHAR(20)
) ENGINE INNODB DEFAULT CHARSET = UTF8;
# 插入数据
insert into TEST_INNODB_LOCK values(1,'a');
insert into TEST_INNODB_LOCK values(2,'b');
insert into TEST_INNODB_LOCK value (3,'c');
insert into TEST_INNODB_LOCK value (4,'d');
结果:
image
创建索引
CREATE INDEX INDEX_LOCK_A ON TEST_INNODB_LOCK(a);
CREATE INDEX INDEX_LOCK_B ON TEST_INNODB_LOCK(b);
# 自动提交变成手动提交
set autocommit = 0;
演示行锁(写&读)
- 在一个窗口控制台执行:
update test_innodb_lock set b='a1' where a = 1;
结果:
image
-
新的控制台窗口:
结果:
image
新开的窗口控制台看到的是旧数据,这是因为 a = 1 的这行记录被 之前的窗口执行的 SQL语句抢到了锁,且没有执行
commit
提交操作。所以后面的窗口控制台看到的是旧数据。这就是 MySQL 隔离级别中的"读已提交"。
4.在的旧的窗口控制台执行
commit;
结果:
image
新的控制台窗口已经读取到最新数据
行锁(写&写)
- 一个控制台窗口console执行
update test_innodb_lock set b='a2' where a = 1;
select * from test_innodb_lock;
image
image
这时候并没有 commit 提交,锁是console持有的
- console_1 也执行修改
image
console_1 一直处于阻塞状态,因为console还没有执行 commit,还持有锁。console_1 抢不到 a = 1 这行记录的锁,因此一直阻塞等待。
-
console执行commit 操作
image
执行update成功!
表锁
- 当索引失效的时候,行锁会升级成表锁
- 索引失效的场景:
- 对索引自动 or
- 手动的换型。比如 integer变成就变成了 String