1. mysql锁知多少

我们进行insert,update,delete,select会加锁吗,如果加锁,加锁步骤是什么,加的什么类型的锁?

行锁里面LOCK_REC_NOT_GAP,LOCK_GAP,LOCK_ORDINARY(Next-Key Lock),LOCK_INSERT_INTENTION这都是些什么锁。

锁是在数据库中是怎么构成的,锁之间兼容与互斥关系

表上有无唯一索引,增删改动作加索引步骤有何区别

死锁是怎么形成的,如何分析

2. 前方高能

这是一篇冗余啰嗦的文章,如果要完整看完,保持耐心,或者自动忽略标记为非重点的内容

3. 锁类型

在InnoDB内部用uint32类型数据表示锁的类型, 最低的 4 个 bit 表示 lock_mode, 5-8 bit 表示 lock_type(目前只用了 5 和 6 位,大小为 16 和 32 ,表示 LOCK_TABLE 和 LOCK_REC), 剩下的高位 bit 表示行锁的类型record_lock_type

record_lock_type

lock_type

lock_mode

我们说锁的时候,一般都是讲什么lock_mode的record_lock_type锁。因为我们很少分析表锁,一般分析行锁。比如LOCK_S的LOCK_REC_NOT_GAP锁,表示共享的记录锁(非间隙锁)

3.1 lock_mode

3.1.1 lock_is/lock_ix(非重点)

LOCK_IS: 表级锁,意向共享锁。表示将要在表上加共享锁。

LOCK_IX:表级锁,意向排他锁。表示是将要在表上加排他锁。

当对记录加LOCK_S或LOCK_X锁的时候,要确保在表上加了LOCK_IS或LOCK_IX锁。

3.1.2 lock_s

表共享锁、也是行共享锁

3.1.2.1 表共享锁(非重点)

ALTER语句第一阶段,当ALTER语句不能ONLINE执行的时间添加

3.1.2.2 行共享锁

事务读在隔离级别为SERIALIZABLE时会给记录加 LOCK_S 锁

SELECT … IN SHARE MODE

普通insert语句遇到duplicate key(普通INSERT语句如果没有duplicate key是不用加行锁的,当遇到duplicate key就需要加LOCK_S锁。 5.6版本加的是LOCK_S类型的LOCK_REC_NOT_GAP锁,导致了一个bug,5.7版本改为了LOCK_S类型的LOCK_ORDINARY锁,更严格了。具体可以参考如下链接:https://m.aliyun.com/yunqi/articles/50886 。这里水很深,小心淹死,后续会举例说明(总共4种 1.三事务并行插入相同记录,事务1回滚(有无ON DUPLICATE KEY UPDATE,两种不同隔离级别)2. 2个事务,事务1插入记录,事务2插入不同记录,事务1插入记录(或者事务1,2都只插入1条,速度够快) 3. 事务1,2,3都做删除,同一条记录 4. 事务1 删除1条记录,事务2,3插入同一条记录,为什么不死锁(on duplicate update 不会死锁(RR隔离级别),如果没有on duplicate update 就会死锁。 有on duplicate update RC隔离级别还未知) ))

3.1.3 lock_x

表排他锁、也是行排他锁

3.1.3.1 表排他锁(非重点)

3.1.3.2 行排他锁

UPDATE/DELETE需要阻止并发对同一行数据进行修改语句的执行

3.2 record_lock_type

3.2.1 LOCK_ORDINARY (next-key lock)

锁住记录本身和记录之前的 gap。当用RR隔离级别的时候,为了防止当前读语句的幻读使用。比如update t set a=3 where b>=4, b列有索引,会锁住b=4的行,并且b>4的间隙。(查看锁信息的时候,表现为lock_mode X,比较奇怪。应该叫next-key lock 或者lock_ordinary。我也是一脸懵逼)

3.2.2 LOCK_GAP(间隙锁)

只锁住索引记录之间或者第一条索引记录前或者最后一条索引记录之后的范围,并不锁住记录本身(查看锁信息的时候,表现为lock_mode X locks gap before rec. lock_mode还有可能是S)

你可以通过切换到RC隔离级别,或者开启选项innodb_locks_unsafe_for_binlog来避免GAP锁。这时候只有在检查外键约束或者duplicate key检查时才会使用到GAP LOCK。

例如在RR隔离级别下,非唯一索引条件上的等值当前读,会在等值记录上加NEXT-KEY LOCK同时锁住行和前面范围的记录,同时会在后面一个值上加LOCK_GAP锁住下一个值前面的范围。下面的例子就会在索引i_c2上给c2 = 5上NEXT-KEY LOCK(LOCK_ORDINARY|LOCK_X),同时给c2 = 10加上LOCK_GAP|LOCK_X锁。这里是因为非唯一索引,对同一个值可以多次插入,为确保当前读的可重复读,需要锁住前后的范围,确保不会有相同等值插入。

create table t1(c1 int primary key, c2 int, c3 int, index i_c2(c2));

insert into t1 values(1, 2, 3), (2, 5, 7), (3, 10, 9);

set tx_isolation='repeatable-read';

select * from t1 where c2 = 5 for update;

3.2.3 LOCK_REC_NOT_GAP(记录锁)

仅锁住记录行,不锁范围。(查看锁信息的时候,表现为lock_mode X locks rec but not gap。 lock_mode还有可能是S)

RC隔离级别下的当前读大多是该方式。同时在上述例子中,RR隔离级别下,非唯一索引上的等值当前读,也会给主键上对应行加LOCK_X|LOCK_REC_NOT_GAP锁

3.2.4 LOCK_INSERT_INTENTION(插入意向锁)

插入意向锁,当插入索引记录的时候用来判断是否有其他事务的范围锁冲突,如果有就需要等待。插入意向锁之间并不冲突,在一个GAP锁上可以有多个意向锁等待。主要表明我要在某某间隙插入记录,如果不想幻读,别来这个区间读。或者,某某事务已经在这个区间加了锁,我就等待,避免造成幻读。也就是GAP锁会阻塞插入意向锁。

4. 事务隔离级别和行锁

快照读和当前读,快照读使用MVCC读取数据记录某一个版本数据,不需要加锁。当前读读取最新数据,需要对记录或者某一个查询范围加锁。(某个版本的数据不会变,当然不用加锁(如果不是Serializable级别,所有普通select都是mvcc读,无需加锁)。如果是当前读,存在多个事务同时操作,需要锁来保证)

InnoDB支持的隔离级别有:

Read Uncommited

可以读未提交记录

Read Committed (RC)

读取已提交数据。会存在幻读。

Repeatable Read (RR)

可重复读。当前读的时候,部分语句会加范围锁,保证当前读的可重复。

Serializable

可串行化。不存在快照读,所有读操作都会加锁。

5. 加锁分析

mysql加锁2个目的:

当前读,避免多个事务同时操作某一行数据

隔离级别要求,比如RR隔离级别,要求可以重复读,mysql还要求实现避免幻读(如果主从同步模式是row-Statement),会加间隙锁

5.1 准备环境

打开锁监控

set GLOBAL innodb_status_output=ON;

set GLOBAL innodb_status_output_locks=ON;

具体可以参考这篇文章:

http://www.ywnds.com/?p=9767

查看和修改隔离级别(需要的时候改动)

查看 select @@tx_isolation;

修改当前会话:set tx_isolation='repeatable-read';

查看和修改锁等待时间(打开会话后修改,便于观察)

查看 select @@innodb_lock_wait_timeout

设置 set innodb_lock_wait_timeout=1000;

人为停止表的purge操作

flush tables tbname for export (会加表锁,没啥用,本来想让停止purge然后看看插入和删除操作加锁是否有区别)

可以google一把什么是purge操作(删除的记录并不会立刻消失,会有另外一个任务来进行清理)

准备数据

create table t(c1 int primary key, c2 int, c3 int, c4 int, unique index i_c2(c2), index i_c3(c3));

insert into t values (10, 11, 12, 13), (20, 21, 22, 23), (30, 31, 32, 33), (40, 41, 42, 43);

5.2 加锁分析

无论select, update 还是delete都是要找到数据之后,才能够加锁。而mysql加锁是加在索引上,那么查询条件就是我们分析加锁的关键了,查询条件的不同会导致使用不同的索引。我们从查询条件的维度来开始分析吧。(如果不懂mysql索引结构和加锁逻辑,可以先查看如下文章补习下:《非常好的加锁逻辑分析》:http://hedengcheng.com/?p=771

《mysql索引介绍》:https://blog.csdn.net/u010558660/article/details/53414456)

5.2.1 查询条件为主键等值

select * from t where c1 = 20 for update;

只需要在c1 = 20的主键记录上加X锁即可,加锁为LOCK_X|LOCK_REC_NOT_GAP(RC(read-committed)还是RR(repeatable-read)都一样)

update t set c4 = 12 where c1 = 20;(未更新索引列)

只需要在c1 = 20的主键记录上加X锁即可,加锁为LOCK_X|LOCK_REC_NOT_GAP(RC,RR一样。以下如果未说明不一样,就是一样)

update t set c2 = 12 where c1 = 20;(更新了索引列)

除了主键记录加X锁,还需要在c2的索引上加LOCK_X|LOCK_REC_NOT_GAP。这里细想以下,可能引起死锁。因为先获得主键X锁,然后才获得C2索引的X锁,如果另外一个事务(针对同一条记录),先获得C2索引的X锁,后获得主键X锁,就会引起死锁(后续会说明)

delete from t where c1 = 20;

对主键、各个索引对应的记录都要加X锁,LOCK_X|LOCK_REC_NOT_GAP。主键,C2,C3索引列都加锁

5.2.2 查询条件为主键范围

select * from t where c1 >= 20 for update;

1.1 RC隔离级别:会分别对c1 in (20, 30, 40)加锁LOCK_X|LOCK_REC_NOT_GAP

1.2 RR隔离级别:这里会对c1=20加X锁(LOCK_X|LOCK_REC_NOT_GAP),对c1=30, c1=40对应的行加exclusive next-key lock(LOCK_X|LOCK_ORDINARY),同时会对表示记录上界的’supremum’加exclusive next-key lock。这样做到阻塞其他事务对c1>=20的加锁操作

image.png

如上图所示:20行record_lock锁,30行next-key lock(锁住的是30和gap3间隙),40行和30行雷同(锁住40行和gap4间隙)。40行前面有一个gap5,这个是记录上界supremum(可以看做是无穷大)的next-key lock锁住的。

update t set c2 = c2 + 1 where c1 >= 20;

2.1 RC隔离级别:会分别对c1 in (20, 30, 40)依次对主键行加X锁,对应的索引行做加X锁操作

2.2 RR隔离级别:对主键c1=20加X锁,i_c2索引行加X锁,然后对c1=30,c1=40的主键行加exclusive next-key lock(LOCK_X|LOCK_ORDINARY),同时对应的i_c2索引行加X锁,最后对表示记录上界的’supremum’加exclusive next-key lock。(与RC区别是,主键上面的GAP会被锁住)

5.2.3 查询条件为唯一索引等值

update t set c4 = 12 where c2 = 21;(未更新索引列)

对唯一索引上数据加X锁(LOCK_X|LOCK_REC_NOT_GAP),然后对应的主键行也需要加X锁

update t set c3 = 12 where c2 = 21; (更新了索引列)

依次对唯一索引数据、主键行、索引数据加X锁。

delete from t where c2 = 21;

会对唯一索引数据加X锁,根据唯一索引找到主键行后,会再依次对主键行、唯一索引、索引数据加X锁

以上3小点,RC和RR隔离级别加锁行为一样。

5.2.4 查询条件为唯一索引范围

select * from t force index(i_c2) where c2 >= 21 for update;

1.1 RC隔离级别:对满足条件的唯一索引、主键记录加X锁

1.2 RR隔离级别:那么会对c2 in (21, 31, 41)分别加exclusive next-key lock,对应主键行加X锁,同时对i_c2上’supremum’ record加exclusive next-key lock。如下图所示:

image.png

c2索引上21,31,41行都是next-key lock(为什么21行要next-lock锁,理论上record-lock锁就应该可以了,这里是因为21行可能已经删除还没有purge,需要锁住间隙,我猜的)。 gap5也被锁住,是无穷大的next-key lock。

主键索引上,20,30,40record lock。

update t force index (i_c2) set c4 = 1 where c2 >= 21;

与1加锁模式一样

update t force index (i_c2) set c3 = 1 where c2 >= 21;(更新索引列)

与2模式一样,增加c3索引上面22,32,42记录锁

delete from t where c2 >= 41;

RC隔离级别:c2索引满足条件的41记录record锁,对应的主键索引40行record锁,对应的c3索引42记录record锁

RR隔离级别:上述语句选择了i_c2索引,会对c2 = 41加exclusive next-key lock,对应主键行加X锁,i_c2,i_c3上数据行进行加X锁操作,对i_c2上’supremum’ record加exclusive next-key lock。

5.2.5 查询条件为非唯一索引

RC隔离级别: 与唯一索引相同

RR隔离级别:

查询条件为非唯一索引等值

1.1 select * from t where c3 = 22 for update;

会对c3 =22在i_c3索引上加exclusive next-key lock(LOCK_X|LOCK_ORDINARY),对应主键加X锁(LOCK_X|LOCK_REC_NOT_GAP),然后在下一条记录上加exclusive gap lock(LOCK_X|LOCK_GAP)。即该语句会锁定范围(11, 31)

1.2 update t set c4 = 2 where c3 = 22;

加锁与上述FOR UPDATE一致

1.3 update t set c2 = 2 where c3 = 22;(更新索引列)

除了上述锁,对c1 = 20对应的唯一索引(i_c2)行加X锁

查询条件为非唯一索引范围

这里加锁与唯一索引的当前读范围查询一致

5.2.6 查询条件上无索引

select * from t where c4 = 23 for update;

RC隔离级别:会依次对c1 in (10, 20, 30, 40)依次加X锁,分析是否满足条件,不满足即释放。为c1 = 10行加锁,不满足条件释放锁;c1=20加锁,满足条件,保留锁;c1=30加锁,不满足条件,释放;c1=40行加锁,不满足条件,释放

RR隔离级别:c1上的记录都加record锁,所有的gap都加间隙锁。这个表相当于被锁死了,只能快照读,其他的都干不了。(原因是,没办法确定要锁住哪一行或者哪个范围。因为c4=23可能出现在c1索引的任何位置,假设你锁住了20行(20行的c4等于23)和20行的间隙,有的会话可能直接将40行的c4改为了23,就会有引起数据污染(RR隔离级别,row-statement的bin log)。如果c4上存在索引,那就是有一个控制点,在这个点上锁记录或者锁范围都是有的放矢。)

5.2.7 Serializable 级别加锁分析

Serializable的加锁与RR隔离级别下一致,不同点是Serializable下普通SELECT语句查询也是当前读。例如下面语句:

select * from t where c1 = 20就会对c1=20的主键行加S锁(LOCK_S|LOCK_REC_NOT_GAP)。

mysql ix锁_mysql锁详解相关推荐

  1. mysql status改变_mysql 配置详解mysql SHOW STATUS 详解

    1. back_log 指定MySQL可能的连接数量.当MySQL主线程在很短的时间内得到非常多的连接请求,该参数就起作用,之后主线程花些时间(尽管很短)检查连接并且启动一个新线程. back_log ...

  2. mysql 流复制_MySQL系列详解六:MySQL主从复制/半同步演示-技术流ken

    前言 随着技术的发展,在实际的生产环境中,由单台MySQL数据库服务器不能满足实际的需求.此时数据库集群就很好的解决了这个问题了.采用MySQL分布式集群,能够搭建一个高并发.负载均衡的集群服务器.在 ...

  3. mysql配置文件说明_mysql配置文件详解说明

    mysql配置文件http://www.doczj.com/doc/ef8ad6026c175f0e7cd1371f.htmlf详解说明 MySQL配置文件http://www.doczj.com/d ...

  4. mysql 实例复制_MySQL 复制详解及简单实例

    MySQL 复制详解及简单实例 主从复制技术在MySQL中被广泛使用,主要用于同步一台服务器上的数据至多台从服务器,可以用于实现负载均衡,高可用和故障切换,以及提供备份等等.MySQL支持多种不同的复 ...

  5. mysql怎么约束_MySQL 约束详解

    MySQL 约束详解 MySQL 中的约束是用来保证数据的完整性的机制.数据完整性一般有以下三种形式: 实体完整性:保证表中有一个主键. 域完整性:保证数据每列的值满足特定条件. 引用完整性:保证两张 ...

  6. mysql import 命令_MySQL命令详解:mysqlimport

    MySQLimport位于MySQL/bin目录中,是MySQL的一个载入(或者说导入)数据的一个非常有效的命令行工具. 使用mysqlimport -?命令,可以查看mysqlimport的具体参数 ...

  7. mysql 执行时间 配置文件_mysql配置文件详解

    [client] user = root host = localhost password = password [mysqld] federated #开启Federated存储引擎 ###### ...

  8. mysql 主从复制讲解_MySQL主从复制详解

    前言: 在MySQL中,主从架构应该是最基础.最常用的一种架构了.后续的读写分离.多活高可用架构等大多都依赖于主从复制.主从复制也是我们学习MySQL过程中必不可少的一部分,关于主从复制的文章有很多, ...

  9. mysql字符集解释_MySQL字符集详解

    一.MySQL字符集编码简单介绍 在使用MySQL时要注意6个需要编码的地方:系统的编码.客户端.服务端.库.表.列.字符集编码不仅影响数据存储,还影响client程序和数据库之间的交互.在mysql ...

  10. mysql 连接字符集_MySQL字符集详解

    一.MySQL字符集编码简单介绍 在使用MySQL时要注意6个需要编码的地方:系统的编码.客户端.服务端.库.表.列.字符集编码不仅影响数据存储,还影响client程序和数据库之间的交互.在mysql ...

最新文章

  1. apex英雄机器人探路者怎么玩_《Apex英雄》探路者机器人怎么玩 探路者机器人技能特性及玩法...
  2. python3爬虫基础学习
  3. STM32-通用定时器基本定时功能
  4. 并发编程-26 高并发处理手段之服务降级与服务熔断 + 数据库切库分库分表
  5. 微信小程序学习笔记(六)
  6. hive 小文件数据合并
  7. Java | Python 流程控制对比
  8. Ubuntu之Docker安装
  9. android系统 wifi,Android系统wifi分析-手动连接过程
  10. 中gcd函数_算法|博弈论入门(函数讲解+真题模板)
  11. 千万别被“读书无用”给害了
  12. 突破性能极限,阿里云神龙最新ASPLOS论文解读
  13. python 广告分析算法_[Python]研究广告渠道的特征数据与结果数据的相关性, 并对渠道作出评分模型...
  14. SSM使用拦截器功能
  15. VSCode 离线安装中文语言包
  16. 【喵迹 Pro】GPS轨迹记录安卓APP使用说明
  17. matlab画中国地图深浅,科学网—MATLAB绘制中国地图 - 栾威的博文
  18. 【硕博士推荐】国内有哪些不错的CV(计算机视觉)团队?
  19. 如何下载ScienceDirect(Elsevier)文献的补充材料
  20. 小米 2015 北京 研发面试

热门文章

  1. java 背单词系统_快速高效背单词系统方法论
  2. AAE 对抗自编码(一)
  3. Social Recommendation with Strong and Weak Ties 学习笔记
  4. 2019 年技术大趋势预测
  5. java bean 转bean_如何用Bull转换任意类型的Java Bean
  6. Android烂笔头
  7. (一)计网五层模型概述
  8. linux 心脏滴血漏洞,漏洞bash近日“破壳”,当心再次“心脏出血”
  9. Nginx的alias/root/try_files实战
  10. 喝王老吉可延长寿命大约10%?