五分钟了解Mysql的行级锁——《深究Mysql锁》
延伸阅读:
三分钟了解Mysql的表级锁
一分钟深入Mysql的意向锁
mysql锁相关讲解及其应用——《深究mysql锁》了解锁前,一定要先看这篇,了解什么是MVCC,如果我们学习锁,没有MVCC的知识,理解起来会总觉得不明朗。本来我的这个只是个记录,并不是专门的讲给别人看的,后发现有不少人看,我还是专门加上这篇文章的链接。
我们首先需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的。所以像Mysql的默认引擎MyISAM和第三方插件引擎 InnoDB的锁实现机制是有区别的。
Mysql有三种级别的锁定:表级锁定、页级锁定、行级锁定
#一、定义
- 每次锁定的是一行数据的锁机制就是行级别锁定(row-level)。行级锁定不是MySQL自己实现的锁定方式,而是由其他存储引擎自己所实现的
#二、优缺点
1. 优点
- 由于锁粒度小,争用率低,并发高。
2. 缺点
- 实现复杂,开销大。
- 加锁慢、容易出现死锁
#三、支持存储引擎
- 使用行级锁定的主要有InnoDB存储引擎,以及MySQL的分布式存储引擎NDBCluster
#四、行级锁类型
InnoDB的行级锁定同样分为两种类型:共享锁和排他锁,而在锁定机制的实现过程中为了让行级锁定和表级锁定共存,InnoDB也同样使用了**意向锁(表级锁定)**的概念,也就有了意向共享锁和意向排他锁这两种。
意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行(或者某些行)上面添加一个排他锁的话,则先在表上面添加一个意向排他锁。
意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。所以,可以说InnoDB的锁定模式实际上可以分为四种
:共享锁(S)
,排他锁(X)
,意向共享锁(IS
)和意向排他锁(IX)
锁模式的兼容性:
#五、行级锁定实现方式
InnoDB行锁是通过给索引上的索引项加锁
来实现的。所以,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。其他注意事项:
- 在不通过索引条件查询的时候,InnoDB使用的是表锁,而不是行锁。
- 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以即使是访问不同行的记录,如果使用了相同的索引键,也是会出现锁冲突的。
- 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
- 即便在条件中使用了索引字段,但具体是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
隐式加锁:
- InnoDB自动加意向锁。
- 对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加
排他锁(X)
; - 对于普通SELECT语句,InnoDB不会加任何锁;
显示加锁:
- 共享锁(S):
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
- 排他锁(X) :
SELECT * FROM table_name WHERE ... FOR UPDATE
用SELECT … IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。
但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT… FOR UPDATE方式获得排他锁。
InnoDB如何加表锁:
在用 LOCK TABLES对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁。
SET AUTOCOMMIT=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
[do something with tables t1 and t2 here];
COMMIT;
UNLOCK TABLES;
既然都用表锁了,怎么不选择MyISAM引擎呢!
#六、间隙锁
####1. 间隙锁定义:
nnodb的锁定规则是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的空域空间上标记锁定信息而实现的。 Innodb的这种锁定实现方式被称为间隙锁
,因为Query执行过程中通过范围查找的话,它会锁定整个范围内所有的索引键值,即使这个键值并不存在。
例:假如emp表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:
mysql> select * from emp where empid > 100 for update;
是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
2. 间隙锁的缺点:
- 间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害
- 当Query无法利用索引的时候, Innodb会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低;
- 当Quuery使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所指向的数据可能有部分并不属于该Query的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键;
- 当Query在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定
####3 . 间隙锁的作用:
- 防止幻读,以满足相关隔离级别的要求。
- 为了数据恢复和复制的需要。
####4. 注意
- 在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。
- InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁。
#七、查看行级锁争用情况
执行SQL:mysql> show status like 'InnoDB_row_lock%';
mysql> show status like 'InnoDB_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| InnoDB_row_lock_current_waits | 0 |
| InnoDB_row_lock_time | 0 |
| InnoDB_row_lock_time_avg | 0 |
| InnoDB_row_lock_time_max | 0 |
| InnoDB_row_lock_waits | 0 |
+-------------------------------+-------+
如果发现锁争用比较严重,还可以通过设置InnoDB Monitors 来进一步观察发生锁冲突的表、数据行等,并分析锁争用的原因。如:
设置监视器:mysql> create table InnoDB_monitor(a INT) engine=InnoDB
;
查看:mysql> show engine InnoDB status
;
停止查看:mysql> drop table InnoDB_monitor
;
具体参考:InnoDB Monitor
#八、死锁
如何发现死锁: 在InnoDB的事务管理和锁定机制中,有专门检测死锁的机制,会在系统中产生死锁之后的很短时间内就检测到该死锁的存在
- 回滚较小的那个事务
- 在REPEATABLE-READ隔离级别下,如果两个线程同时对相同条件记录用SELECT…FOR UPDATE加排他锁,在没有符合该条件记录情况下,两个线程都会加锁成功。程序发现记录尚不存在,就试图插入一条新记录,如果两个线程都这么做,就会出现死锁。这种情况下,将隔离级别改成READ COMMITTED,就可避免问题。
- 当产生死锁的场景中涉及到不止InnoDB存储引擎的时候,InnoDB是没办法检测到该死锁的,这时候就只能通过锁定超时限制参数InnoDB_lock_wait_timeout来解决。
#九、优化行级锁定
五分钟了解Mysql的行级锁——《深究Mysql锁》相关推荐
- [MySQL] mysql 的行级显式锁定和悲观锁
[MySQL] mysql 的行级显式锁定和悲观锁 隐式和显式锁定: 1.innodb是两阶段锁定协议,隐式锁定比如在事务的执行过程中.会进行锁定,锁只有在commit或rollback的时候,才会同 ...
- mysql 表级别的锁和行级别的_MySQL 表锁和行锁机制
案例分析 目前,MySQL常用的存储引擎是InnoDB,相对于MyISAM而言.InnoDB更适合高并发场景,同时也支持事务处理.我们通过下面这个案例(坑),来了解行锁和表锁. 业务:因为订单重复导入 ...
- 2 万字 + 30 张图搞懂 MySQL 的行级锁!
不是很多人都对 MySQL 加行级锁的规则搞的迷迷糊糊,对记录一会加的是 next-key 锁,一会加是间隙锁,一会又是记录锁. 坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如何用命令分 ...
- MySQL数据库行级锁之行锁
行级锁 行级锁,每次操作锁住对应的行数据.锁定粒度最小,发生锁冲突的概率最低,并发度最高.应用在InnoDB存储引擎中. InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而 ...
- 使用mysql命令行的工具_[MySQL]命令行工具和基本操作
一 MySQL命令行工具 (查看帮助 ---help,或 -?) 1)MySQL MySQL是一个简单的SQL外壳(有GNUreadline功能).它支持交互式和非交互式使用.当交互使用时,查询结果 ...
- mysql 命令行 换行_在MySQL命令行中使用SQL语句的规则
规则1: SQL语句必须以分号(;)或者(\G)结束 分号(;)是SQL语句的结束标志.如果遗忘了分号,而直接按下回车键时,在MySQL客户端上将显示如下 mySQL> SELECT * FRO ...
- MySQL计算表行数_计算MySQL表中行数的最快方法?
让我们首先来看一个创建表,添加记录并显示它们的示例.CREATE命令用于创建表.mysql> CREATE table RowCountDemo -> ( -> ID int, -& ...
- mysql父行指那一行,MySQL中给定父行找到所有子行的解决方案
前言 备注:测试数据库版本为MySQL 8.0 如需要scott用户下建表及录入数据语句,可参考: scott建表及录入数据sql脚本 一.需求 找到直接及简介(即JONES下属的下属)为JONES工 ...
- Mysql 命令行模式访问操作mysql数据库
使用环境 在cmd模式下输入 mysql --version (查看mysql安装的版本). 完整的命令可以通过mysql --help来获取. 本测试使用的Mysql版本是mysql5, 本测试使用 ...
最新文章
- P1083 [NOIP 2012]借教室
- Supermemo背单词7周年纪念
- xfce4环境下gdm3更换背景图片
- 8、oracle数据库下的索引
- [原创]android使用代码生成LayerDrawable的方法和注意事项
- 新建maven的pom.xml第一行出错的解决思路
- Android 系统性能优化(27)---内存分析工具
- img打 webpack_webpack 打包js中的img路径问题
- python数据检索_python – Hachoir – 从组中检索数据
- Spring: 读取 .properties 文件地址,json转java对象,el使用java类方法相关 (十三)
- SystemMenu添加Item
- 解决tomcat能起开,但是访问不进8080首页的问题
- sqlserver数据库分组查询
- iOS---实现在屏幕上实时绘图的简单效果---CAShaperLayer和UIBezierPath的简单运用
- Intel网卡MAC地址更改方法
- 北京消费者买15类节能商品可获补贴 单件最高800元
- vue组件中引入public文件,build打包后找不到资源报错404
- python统计英文单词个数_统计英文单词的个数的python代码 及 字符串分割
- 解决麒麟V10上传文件乱码问题
- IntelliJ IDEA V2022.1版本亮点——改进框架与技术
热门文章
- Python 打包 exe 程序避坑指南:没有安装包也能运行小程序啦~开心
- [ARM-assembly]-ARM ASM内联汇编学习
- e0312 不存在用户定义的_VistaPro创建自定义变量
- 【安全漏洞】某CMS后台防护逻辑漏洞导致GETSHELL
- vSphere开发指南1——vSphere Automation API
- Dubbo管控台Windows安装
- MySQL查看数据表
- python调用dll函数_从Python调用DLL函数
- java oss 批量传输_初步使用阿里云OSS对象存储功能
- Python多线程介绍及实例