MySQL表锁、行锁、排它锁及共享锁的使用详解


Posted in MySQL onApril 02, 2022

前言

事务隔离级别的实现原理:简单来说就是各种锁机制和MVCC多版本并发控制

我们学习知识的时候,需要了解知识点出现的原因,什么情况下能用到这个知识

我们说到事务,就得说到事务的ACID特性,说到隔离性的时候,事务要能够允许并发执行,并发执行为了同时保证数据的安全性,一致性和并发的效率,就需要设置事务的隔离级别

一、事务隔离机制的选择

  • 如果我们完全不管,使用未提交读的事务隔离机制,任由这些线程并发操作数据库,那就会出现脏读(读取了未commit的数据)、不可重复读(两次查询值不同)、幻读(两次查询数据量不同)等问题,数据的安全性最低,优点是并发效率非常高,一般不会使用
  • 如果我们串行化(靠锁实现),通过锁给所有的事务都排个序,虽然数据的安全性提高了,并发的效率就太低了,一般也不会使用
  • 所以我们一般用的是已提交读、可重复读这两个隔离级别,平衡了数据的安全性,一致性以及并发的效率 ,是由MVCC多版本并发控制实现的(MVCC是已提交读和可重复读的原理,锁是串行化的原理)

二、表级锁&行级锁

表级锁:对整张表加锁。开销小(因为不用去找表的某一行的记录进行加锁,要修改这张表,直接申请加这张表的锁),加锁快,不会出现死锁;锁粒度大,发生锁冲突的概率高,并发度低

行级锁:对某行记录加锁。开销大(需要找到表中相应的记录,有搜表搜索引的过程),加锁慢,会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度高

MySQL表锁、行锁、排它锁及共享锁的使用详解

InnoDB存储引擎支持事务处理,表支持行级锁定,并发能力更好

  1. InnoDB行锁是通过给索引上的索引项加锁来实现的,而不是给表的行记录加锁实现的,这就意味者只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁
  2. 由于InnoDB的行锁实现是针对索引字段添加的锁,不是针对行记录加的锁,因此虽然访问的是InnoDB引擎下表的不同行,但如果使用相同的索引字段作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行
  3. 即使SQL中使用了索引,但是经过MySQL的优化器后,如果认为全表扫描比使用索引效率高,此时会放弃使用索引,因此也不会
    使用行锁,而是使用表锁,比如对一些很小的表,MySQL就不会去使用索引

三、排它锁(Exclusive)和共享锁(Shared)

  • 排它锁,又称为X锁,写锁
  • 共享锁,又称为S锁,读锁

读读(SS)之间是可以兼容的,但是读写(SX、SX)之间,写写(XX)之间是互斥的

对事务加X和S锁之间有以下的关系:

  • 一个事务对数据对象A加了 S 锁,可以对A进行读取操作但不能进行update操作,加锁期间其它事务能对A加S锁但不能加 X 锁
  • 一个事务对数据对象A加了 X 锁,就可以对A进行读取和更新,加锁期间其它事务不能对A加任何锁

显示加锁:select … lock in share mode强制获取共享锁,select … for update获取排它锁

1. 测试不同事务之间排它锁和共享锁的兼容性

我们先查看表的SQL以及内容

MySQL表锁、行锁、排它锁及共享锁的使用详解

查看隔离级别:

MySQL表锁、行锁、排它锁及共享锁的使用详解

首先开启一个事务,给id=7的数据加上排它锁

MySQL表锁、行锁、排它锁及共享锁的使用详解

在用另一个客户端开启事务

MySQL表锁、行锁、排它锁及共享锁的使用详解

我们用另一个事务的服务线程给id=7的数据加上排它锁,阻塞了

MySQL表锁、行锁、排它锁及共享锁的使用详解

我们尝试给id=7的数据加上共享锁,还是阻塞了

总结:不同事务之间对于数据的锁,只有SS锁可以共存,XX、SX、XS都不能共存

2. 测试行锁加在索引项上

其实行锁是加在索引树上的

MySQL表锁、行锁、排它锁及共享锁的使用详解

用表的无索引字段作为过滤条件

MySQL表锁、行锁、排它锁及共享锁的使用详解

事务2现在同样想获取这条记录的排它锁,可想而知地失败了;那现在事务2获取chenwei的记录的排它锁,试试能不能成功

MySQL表锁、行锁、排它锁及共享锁的使用详解

InnoDB是支持行锁的,刚才以主键id为过滤条件时,事务1和事务2获取不同行的锁是可以成功的。然而现在我们发现获取name为chenwei的排它锁也获取不到了,这是为什么?我们解释一下:

InnoDB的行锁是通过给索引项加锁来实现的,而不是给表的行记录加锁实现的

而我们用name作为过滤条件没有用到索引,自然就不会使用行锁,而是使用表锁。这就意味着只有通过索引检索数据,InnoDB才使用行级锁,否则InnoDB都将使用表锁!!!

我们给name字段加上索引

MySQL表锁、行锁、排它锁及共享锁的使用详解

MySQL表锁、行锁、排它锁及共享锁的使用详解

我们发现,给name加上索引后,两个事务可以获取到不同行的排它锁(for update),再一次证明了InnoDB的行锁是加在索引项上的

MySQL表锁、行锁、排它锁及共享锁的使用详解

因为现在name走的是索引, 通过zhangsan在辅助索引树上找到它所在行记录的id是7,然后到主键索引树上,获取对应行记录的排他锁(个人猜测应该是辅助索引树和主键索引树相应的记录都加了锁)

四、串行化隔离级别测试

(所有的事务都使用排它锁或共享锁,不需要用户手动加锁)

设置串行化隔离级别

MySQL表锁、行锁、排它锁及共享锁的使用详解

两个事务可以同时获取共享锁(SS共存)

MySQL表锁、行锁、排它锁及共享锁的使用详解


现在让事务2插入数据

MySQL表锁、行锁、排它锁及共享锁的使用详解

此时由于insert需要加排它锁,但由于事务1已经对整张表添加了共享锁,事务2无法再对表成功加锁(SX不共存)

rollback一下

MySQL表锁、行锁、排它锁及共享锁的使用详解

因为我们给name加上了索引,以上的select相当于给name为zhangsan的数据加上了行共享锁

事务2 update

MySQL表锁、行锁、排它锁及共享锁的使用详解

事务2不能update,因为此时已经被事务1的共享锁锁住了整个表

事务2在辅助索引树上找zhangsan,找到对应的主键值,然后去主键索引树找到相应的记录,但是发现这行记录已经被共享锁锁住了,事务2可以获取共享锁,但是不能获取排他锁

MySQL表锁、行锁、排它锁及共享锁的使用详解

我们用主键索引id试试能不能update

MySQL表锁、行锁、排它锁及共享锁的使用详解

依然阻塞住了,虽然我们where后面的字段现在使用的id而不是name,但是name也是通过辅助索引树找到对应的主键,再到主键索引树上找相应的记录,而主键索引树上的记录加了锁(个人猜想应该是辅助索引树和主键索引树对应的数据都加了锁)

我们update id=8的数据,成功了。因为我们select的时候,只是给id=7的数据加上了行锁,我们操作id=8的数据当然可以成功

MySQL表锁、行锁、排它锁及共享锁的使用详解

有索引,则使用行锁;没有索引,则使用表锁。

表级锁还是行级锁说的是锁的粒度,共享锁和排他锁说的是锁的性质,不管是表锁还是行锁,都有共享锁和排他锁的区分

总结

到此这篇关于MySQL表锁、行锁、排它锁及共享锁使用的文章就介绍到这了,更多相关MySQL表锁、行锁、排它锁和共享锁内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
Mysql Show Profile
Apr 05 MySQL
MySQL表的增删改查基础教程
Apr 07 MySQL
MySQL infobright的安装步骤
Apr 07 MySQL
详解MySQL集群搭建
May 26 MySQL
正确使用MySQL update语句
May 26 MySQL
MySQL查看表和清空表的常用命令总结
May 26 MySQL
MYSQL数据库使用UTF-8中文编码乱码的解决办法
May 26 MySQL
MySQL命令无法输入中文问题的解决方式
Aug 30 MySQL
浅谈redis的过期时间设置和过期删除机制
Mar 18 MySQL
MySQL去除密码登录告警的方法
Apr 20 MySQL
MySQL GTID复制的具体使用
May 20 MySQL
mysql实现将字符串字段转为数字排序或比大小
Jun 14 MySQL
navicat 连接Ubuntu虚拟机的mysql的操作方法
MySQL中IO问题的深入分析与优化
mysql的Buffer Pool存储及原理
一次Mysql update sql不当引起的生产故障记录
Mysql超详细讲解死锁问题的理解
Nebula Graph解决风控业务实践
MySQL实现配置主从复制项目实践
You might like
php获取bing每日壁纸示例分享
2014/02/25 PHP
php array_merge_recursive 数组合并
2016/10/26 PHP
thinkphp5 URL和路由的功能详解与实例
2017/12/26 PHP
javascript 写类方式之三
2009/07/05 Javascript
jquery 的 $("#id").html() 无内容的解决方法
2010/06/07 Javascript
基于Jquery的简单图片切换效果
2011/01/06 Javascript
javascript实现网页屏蔽Backspace事件,输入框不屏蔽
2015/07/21 Javascript
jquery中ajax处理跨域的三大方式
2016/01/05 Javascript
js和jQuery设置Opacity半透明 兼容IE6
2016/05/24 Javascript
Js获取当前日期时间及格式化代码
2016/09/17 Javascript
DOM 事件的深入浅出(一)
2016/12/05 Javascript
浅谈jQuery的bind和unbind事件(绑定和解绑事件)
2017/03/02 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
关于TypeScript中import JSON的正确姿势详解
2017/07/25 Javascript
bootstrap日期插件daterangepicker使用详解
2017/10/19 Javascript
JavaScript迭代器的含义及用法
2019/06/21 Javascript
JavaScript canvas实现雪花随机动态飘落
2020/02/08 Javascript
在vue中动态修改css其中一个属性值操作
2020/12/07 Vue.js
[00:36]我的中国心——Serenity vs Fnatic
2018/08/21 DOTA
python实现自动重启本程序的方法
2015/07/09 Python
python 中split 和 strip的实例详解
2017/07/12 Python
python使用matplotlib模块绘制多条折线图、散点图
2020/04/26 Python
pygame实现雷电游戏雏形开发
2018/11/20 Python
Django单元测试中Fixtures用法详解
2020/02/25 Python
实例讲解使用CSS实现多边框和透明边框的方法
2015/09/08 HTML / CSS
公司业务主管岗位职责
2013/12/07 职场文书
初中作文评语集锦
2014/12/25 职场文书
继续教育个人总结
2015/03/03 职场文书
2015年大学生入党自荐书
2015/03/24 职场文书
2015年信贷员工作总结
2015/04/28 职场文书
建党伟业观后感
2015/06/01 职场文书
行政处罚决定书
2015/06/24 职场文书
大学生暑期实践报告
2015/07/13 职场文书
Python控制台输出俄罗斯方块移动和旋转功能
2021/04/18 Python
开机音效回归! Windows 11重新引入开机铃声
2021/11/21 数码科技
「偶像大师 MILLION LIVE!」七尾百合子手办开订
2022/03/21 日漫