MySQL

71-MySQL-事务-行级锁

2023-01-09  本文已影响0人  紫荆秋雪_文

一、InnoDB中的行锁

行锁(Row Lock)也称为记录锁,也就是锁住某一行(某条记录 row)。需要注意的是,MySQL 服务器层并没有实现行锁机制行级锁只在存储引擎层实现

二、准备数据

1、创建数据库

CREATE TABLE `student`
(
    `id`    INT NOT NULL,
    `name`  VARCHAR(20) DEFAULT NULL,
    `class` VARCHAR(20) DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB;

2、创建数据

INSERT INTO student
VALUES (1, '张三', '一班'),
       (3, '李四', '一班'),
       (8, '王五', '二班'),
       (15, '赵六', '二班'),
       (20, '钱七', '三班');
聚簇索引示意图.png

三、 InnoDB行锁-记录锁(Record Locks)

记录锁也就是仅仅把一条记录锁上,官方的类型名称为: LOCK_REC_NOT_GAP 。比如把id值为8的那条记录加一个记录锁的示意图如图所示。仅仅是锁住了id值为8的记录,对周围的数据没有影响。

记录锁.png

1、实战

步骤1、Session1,开启手动提交事务,更新id为1的数据
BEGIN ;

UPDATE student
SET name = '张三 1'
WHERE id = 1;
步骤2、Session1,查询数据
SELECT *
FROM student;
Session1查询到了修改后的最新数据.png
步骤3、Session2,开启手动提交事务,查询列表数据
BEGIN ;

SELECT *
FROM student;
Session2查询到的数据依然是就数据.png
步骤4、Session2,修改id为3的数据
UPDATE student
SET name = '李四 1'
WHERE id = 3;
修改id=3的数据👌.png
步骤5、Session2,修改id为1的数据
UPDATE student
SET name = '张三 2'
WHERE id = 1;
执行被阻塞.png
执行被阻塞超时.png
步骤6、Session1和Session2,提交事务
COMMIT ;
image.png image.png
小结:记录锁是有S锁X锁之分的,称之为 S型记录锁X型记录锁

四、 间隙锁(Gap Locks)

MySQLREPEATABLE READ 隔离级别下是可以解决幻读问题的,解决方案有两种,方案一:可以使用 MVCC 方案解决方案二:可以采用 加锁 方案解决。但是方案二有个大问题,就是事务在第一次执行读取操作时,那些幻影记录尚不存在,我们无法给这些 幻影记录 加上 记录锁 。InnoDB提出了一种称之为Gap Locks 的锁,官方的类型名称为: LOCK_GAP ,我们可以简称为 gap锁 。

间隙锁.png

1、实战

步骤1:Session1为不存在记录添加共享锁
BEGIN ;

SELECT *
FROM student
WHERE id = 5 LOCK IN SHARE MODE ;
步骤2:Session2为不存在记录添加排他锁
SELECT *
FROM student
WHERE id = 5 FOR UPDATE ;
SELECT *
FROM student
WHERE id > 20 FOR SHARE ;
SELECT *
FROM performance_schema.data_locks;
image.png

2、实战:插入同间隙数据会阻塞

步骤1:Session1 修改为手动提交事务
COMMIT ;
步骤2:Session1 产看锁情况
SELECT *
FROM performance_schema.data_locks;
步骤3:Session1 为间隙添加排他锁
SELECT *
FROM student
WHERE id = 5 FOR UPDATE ;
步骤4:Session1 产看锁情况
SELECT *
FROM performance_schema.data_locks;
student 表的锁情况.png
步骤5:Session2 修改为手动提交事务
COMMIT ;
步骤6:Session2 在间隙中插入数据
INSERT INTO student
    VALUE (4, 'Raven', '二班');
阻塞超时.png
步骤7:Session1 产看锁情况
SELECT *
FROM performance_schema.data_locks;
image.png
步骤8:可以插入非锁定间隙数据,锁定区间为(3, 8)
INSERT INTO student
    VALUE (16, 'Raven', '三班');

3、实战:插入同一间隙数据会阻塞

步骤1:Session1 开启手动提交事务,并且加间隙锁
BEGIN ;

SELECT *
FROM student
WHERE id = 4 FOR UPDATE ;
步骤2:Session2 开启手动提交事务,并且在同一间隙上加间隙锁
BEGIN ;

SELECT *
FROM student
WHERE id = 5 FOR UPDATE ;
步骤3:Session2 在间隙中添加数据
INSERT INTO student
    VALUE (5, 'Raven-5', '三班');
步骤4:Session1 在间隙中添加数据
INSERT INTO student
    VALUE (4, 'Raven-4', '三班');
造成死锁.png
小结

五、 临键锁(Next-Key Locks)

有时候既想 锁住某条记录 ,又想 阻止 其他事务在该记录前边的 间隙插入新记录 ,所以InnoDB就提出了一种称之为 Next-Key Locks 的锁,官方的类型名称为: LOCK_ORDINARY ,可以简称为next-key锁Next-Key Locks是在存储引擎 innodb 、事务级别在 可重复读 的情况下使用的数据库锁,innodb默认的锁就是Next-Key locks。

image.png
SELECT *
FROM student
WHERE id <= 8 AND id > 3 FOR UPDATE ;

六、插入意向锁(Insert Intention Locks)

一个事务在 插入 一条记录时需要判断一下插入位置是不是被别的事务加了 gap锁 ( next-key锁 也包含 gap锁 ),如果有的话,插入操作需要等待,直到拥有 gap锁 的那个事务提交。但是InnoDB规定事务在等待的时候也需要在内存中生成一个锁结构,表明有事务想在某个 间隙插入 新记录,但是现在在等待。InnoDB就把这种类型的锁命名为 Insert Intention Locks,官方的类型名称为:LOCK_INSERT_INTENTION,我们称为 插入意向锁 。插入意向锁是一种 Gap锁 ,不是意向锁,在insert操作时产生。
插入意向锁是在插入一条记录行前,由INSERT 操作产生的一种间隙锁。该锁用以表示插入意向,当多个事务在同一区间(gap)插入位置不同的多条数据时,事务之间不需要互相等待。假设存在两条值分别为 4 和 7 的记录,两个不同的事务分别试图插入值为 5 和 6 的两条记录,每个事务在获取插入行上独占的(排他)锁前,都会获取 (4, 7) 之间的间隙锁,但是因为数据行之间并 不冲突,所以两个事务之间并不会产生冲突(阻塞等待)

image.png
上一篇 下一篇

猜你喜欢

热点阅读