innodb的锁讲解
发表于:2024-11-22 作者:千家信息网编辑
千家信息网最后更新 2024年11月22日,innodb的锁,我们可以从几个维度来分析,分为级别,类型级别行级锁表级锁类型共享锁(S),也称为写锁, 级别:行级锁意向共享锁(IS),也称为意向写锁 级别:表级锁排他锁(X),也称为读锁 属于行级
千家信息网最后更新 2024年11月22日innodb的锁讲解
- innodb的锁,我们可以从几个维度来分析,分为级别,类型
- 级别
- 行级锁
- 表级锁
- 类型
- 共享锁(S),也称为写锁, 级别:行级锁
- 意向共享锁(IS),也称为意向写锁 级别:表级锁
- 排他锁(X),也称为读锁 属于行级锁 级别: 行级锁
- 意向排他锁(IX),也称为意向读锁 级别: 表级锁
- 行锁的算法
- Record Locks
- Gap Locks
- Next-Key Locks
- Insert intention Locks
- AUTO-INC Locks
- Predicate Locks for Spatial Indexes
- 级别
- 锁的兼容性请看下图
- 我们就先从类型讲起
- 共享锁
- 允许持有锁的事务读取行
- 假如有一个a事务获取了x行的共享锁,这时候b事务也来请求x行的锁,那么会进行一下处理
- 如果b请求的是x行的共享锁,那么会立刻授予,这时候a事务和b事务都拥有x行的共享锁
- 如果b请求的是x的排他锁,那么不会立刻授予,因为共享锁和排他锁是不兼容的
- 排他锁
- 允许持有锁的事务更新或删除行。
- 假如有一个a事务获取了x行的排他锁,这时候b事务也来请求x行的锁,这时候不管b事务请求的锁是共享锁还是排他锁,都不能立即授予,只能等到a事务释放了在x行的排他锁才能授予b事务,因为排他锁与任何的锁都不兼容
- 意向锁的讲述
- innodb支持多粒度锁定,这种锁定允许事务在行级上的锁和表级上的锁同行存在,为了支持在不同粒度上进行操作,innodb存储引擎支持一个额外的锁方式,称之为意向锁,意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁,也就是如果一个事务需要针对记录R来加排他锁,那么就需要对记录R所在的数据库,表,页进行加锁,最后对记录R加排他锁,如果有任何一个部分导致等待,那么该操作需要粗粒度锁的完成。
- 意向锁是表级锁,设计目的主要是为了在下一个事务中揭示下一行将被请求的锁类型,由于innodb存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求。
- 上面的可能不好理解,下面我说一个实际的例子
- 我们有一个student表
- mysql> show create table student;
- +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | Table | Create Table |
- +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | student | CREATE TABLE
student
( id
int(11) NOT NULL AUTO_INCREMENT,student_num
int(11) NOT NULL DEFAULT '0' COMMENT '学号',name
varchar(32) NOT NULL DEFAULT '' COMMENT '学生姓名',- PRIMARY KEY (
id
), - UNIQUE KEY
uqidx_student_num
(student_num
) - ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 |
- +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- 1 row in set (0.00 sec)
- mysql> select * from student;
- +----+-------------+----------+
- | id | student_num | name |
- +----+-------------+----------+
- | 1 | 1 | zhangsan |
- | 2 | 2 | lisi |
- | 3 | 3 | wangwu |
- | 4 | 4 | zhaoliu |
- | 5 | 5 | liqi |
- +----+-------------+----------+
- 5 rows in set (0.00 sec)
- session1
- mysql> start transaction;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from student where student_num=4 for update;
- +----+-------------+---------+
- | id | student_num | name |
- +----+-------------+---------+
- | 4 | 4 | zhaoliu |
- +----+-------------+---------+
- 1 row in set (0.00 sec)
- session2
- mysql> LOCK TABLE student write;
- 这时候我们发现session2一直在等待,因为session2想获取student整个表的写锁,如果session2申请成功了, 它是可以修改student表的任意一行的,那么大家会说session1已经获取了student_num=4的排他锁呢,如果session2申请成功了,那么student_num=4的记录也会被session2修改了,所以说这时候session2肯定是会阻塞的,那么数据库是根据什么方法来判断使得session2被阻塞呢,无非就下面两种方法
- 判断这个表是否被其他事务用表锁给锁住
- 判断这个表的每一行是否有行锁
- 根据前面的讲述,假如我们要针对某一条记录加排他锁的话,那么会在记录对应的表里面先加一个共享排他锁,然后再到记录上面加一个排他锁,这时候我们可以发现session1可以针对student表加了一个共享排他锁了,那么这时候session2发现student上面已经有其他事务加上共享排他锁了,因此会阻塞。如果没有意向锁的话,那session2就要走方法2了,那么就需要判断每一行,那么需要遍历整个表,这种效率非常差,特别碰到表数据量大的时候。
- 意向共享锁
- 事务想要获取一个表中某几行的共享锁
- 意向排他锁
- 事务想要获取一个表中某几行的排他锁
- 请注意:对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的 Select 语句,InnoDB 不会加任何锁,可能有人会有疑问,什么是一般的select,什么是特殊的select呢,一般的select就是select column from table where x=1 特殊的select就是select column from table where x=1 lock in share mode或者select column from table where x=1 for udpate ,前面加共享锁,后者加排他锁
- 共享锁
行锁
- Record Locks
- 记录锁是索引记录上的锁,例如SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;防止任何其他事务插入,更新或删除t.c1的值为10的行
- 记录锁始终锁定索引记录,如果一个表没有定义任何的索引,像这种情况,innodb会创建一个隐藏的聚簇索引并且使用此索引进行记录锁定
- 需要注意的是:
- innodb的记录锁是针对索引加锁,不是针对物理记录加锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,将出现锁冲突
- Gap Locks
- 间隙锁是锁定索引记录之间的间隙,或锁定第一个索引记录之前或最后一个索引记录之后的间隙上。。例如 SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;由于范围内所有现有值之间的间隔都被锁定,因此可以防止其他事务向列t.c1中插入值15,无论该列中是否已有任何此类值。
- 对于使用唯一索引锁定行的语句,不需要使用间隙锁(这不包括搜索条件仅包括多列唯一索引的一些列的情况; 在这种情况下,确实会出现间隙锁定),例如,如果id列是一个唯一索引,那么下面的语句只会在id=100的那行上面加一个索引记录锁,而不会关心别的会话(session)是否在前面的间隙中插入数据。
- SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
- 如果id没有索引或者没有唯一索引,则该语句将锁定前述的间隙
- 间隙锁的主要作用,就是和记录锁组成Next-key锁,解决幻读问题
- 间隙锁在不同的隔离级别下,有着不同的作用范围,能发挥间隙锁作用的,是'REPEATTABLE READ'隔离级别,在这个级别下使用带有间隙锁的Next-Key锁,解决了幻行的问题。这个涉及到了事务隔离级别和一致读的相关信息,后面我也会更新对应的文章
- Next-Key Locks
- next-key锁是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合,也就是相当于Record Locks+Gap Locks
- InnoDB以这种形式实现行级锁,当它查找或扫描表索引的时候,它会在遇到的索引记录上设置共享或排它锁。因此,行级锁实际上是索引记录锁。next-key锁同样会影响索引记录之前的间隙。就是说,next-key 锁就是一个索引记录锁加上索引记录前间隙的间隙锁。如果一个会话拥有记录 R 的索引上面的一个共享锁或独占锁,另一个会话不能在索引顺序中的R之前的间隙中插入新的索引记录。
- 下面我们来看一个表
- mysql> create table goods(
- -> id int not null auto_increment primary key,
- -> title varchar(32) not null default '' comment '商品名称',
- -> classify tinyint not null default 0 comment '商品类型',
- -> index
idx_classify
(classify
) - -> )engine=innodb charset=utf8;
- mysql> insert into goods (
title
,classify
) values ('商品1',1),('商品2',3),('商品3',5),('商品4',8),('商品5',10),('商品6',1),('商品7',3),('商品8',5),('商品9',8),('商品10',10); - mysql> select * from goods;
- +----+----------+----------+
- | id | title | classify |
- +----+----------+----------+
- | 1 | 商品1 | 1 |
- | 2 | 商品2 | 3 |
- | 3 | 商品3 | 5 |
- | 4 | 商品4 | 8 |
- | 5 | 商品5 | 10 |
- | 6 | 商品6 | 1 |
- | 7 | 商品7 | 3 |
- | 8 | 商品8 | 5 |
- | 9 | 商品9 | 8 |
- | 10 | 商品10 | 10 |
- +----+----------+----------+
- 10 rows in set (0.00 sec)
- mysql> select distinct(classify) from goods;
- +----------+
- | classify |
- +----------+
- | 1 |
- | 3 |
- | 5 |
- | 8 |
- | 10 |
- +----------+
- 5 rows in set (0.02 sec)
- #在REPEATTABLE READ隔离级别下,执行查询时,因为Next-Key锁存在,写Next-Key的锁定范围如下
- (-∞,1) 锁定索引项1和1之前的间隙,因为1之前没有其他索引项,所以负无穷
- (1,3) 锁定1和3之前的间隙,不包括1,包括3
- (3,5) 同上
- (5,8) 同上
- (8,10) 同上
- (10,∞) 锁定索引项10和10之后的间隙,因为10之后没有其他索引项,所以为正无穷
- 下面我们就用一个demo来验证一下
- Session1
- mysql> start transaction;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from goods where classify=3 for update;
- +----+---------+----------+
- | id | title | classify |
- +----+---------+----------+
- | 2 | 商品2 | 3 |
- | 7 | 商品7 | 3 |
- +----+---------+----------+
- 2 rows in set (0.00 sec)
- #对于辅助索引,其加的是Next-Key锁,锁定的范围是(1,3),特别需要注意的是,innodb存储引擎还会对辅助索引下一个键值加上gab lock,即还有一个辅助索引范围(3,5)的锁
- Session2
- mysql> start transaction;
- Query OK, 0 rows affected (0.00 sec)
mysql> insert into goods (title
,classify
) select '商品11',4; - #这时候可以看到session2给阻塞了,因为session1的Next-Key的锁定范围是(1,3),(3,5),正好包含了4
- mysql> insert into goods (
title
,classify
) select '商品11',6; - Query OK, 1 row affected (0.00 sec)
- Records: 1 Duplicates: 0 Warnings: 0
- 插入classify=6的就立刻成功了, 因为6不在(1,3),(3,5)的范围内
- Session1
- Insert intention Locks
- Insert intention 锁是插入行之前由INSERT操作设置的一种间隙锁。。此锁表示要插入的意图是多个事务插入到相同的索引间隙时, 如果它们没有插入到间隙中的同一位置, 则不必等待对方。。假设存在值为4和7的索引记录。两个事务分别尝试插入5和6,分别用插入意向锁锁住4和7之间的间隙,然后再取得插入行的排它锁,但是相互不会阻塞,因为这些行是不冲突的。
- AUTO-INC Locks
- AUTO-INC锁是由插入到带有 AUTO_INCREMENT 列的表中的事务所采取的特殊表级锁。。一个最简单的例子,如果一个事务正在向表中插入值,则任何其他事务必须等待对该表执行自己的插入,以便第一个事务插入的行接收连续的主键值。
- Predicate Locks for Spatial Indexes
- innodb支持空间索引,如果使用Next-Key来支持空间索引,则不能满足要求,这是因为普通的索引都是键值类型,意味着索引存在一个方向,这个方向是单向的,要不升序要不降序,这个方向的存在,使得数据库存储引擎可以利用索引进行常规的范围查询
- 但是在空间数据类型上面,这个单向的有序变得失去了作用,因为空间数据是多维多向的,是以区域或空间为范围的,没有确定的方向顺序,所以单向的Next-Key满足不了要求
- 空间索引是建立爱MBR上的,innodb为索引项的MBR增加了一个谓词锁,实现空间索引上的并发控制
- Record Locks
- 参考资料
- 链接:
- https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
- 书籍:
- 高性能MySQ
- MySQL技术内幕 innoDB存储引擎
- 数据库事务处理的艺术 事务管理与并发控制
- 链接:
索引
事务
商品
间隙
意向
级别
数据
范围
空间
类型
支持
阻塞
就是
引擎
存储
一行
作用
数据库
方向
粒度
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
M.ECHO曼音科技软件开发
中国专利在线数据库
国家网络安全宣传周论文
小壳网络技术有限公司
国家网络安全图画简单
最早网络技术
魔兽世界角色转移没选服务器
黄石网络安全宣传周答题福利
数据库的系统安全管理制度
服务器ddr4 品牌
国产ARM服务器出货量
数据库系统和审计学哪个难学
开展国家网络安全周是哪一年
mysql数据库测试
软件开发中什么是泛化
泰拉瑞亚13版本服务器怎么弄
数据库中的VIA
网络安全管理合同
东莞华南软件开发中心软件开发
沭阳工业网络技术保养
搭建局域网共享服务器
基于结果的软件开发原则
酒店网络安全防护
手机用炒股软件开发
网络安全股控
乐器管理的数据库设计
某软件开发企业系一般纳税人
网络安全主题班会一年级
软件开发培训学校机构
带有gpu的服务器玩游戏