mysql锁相关讲解及其应用
一、mysql的锁类型
(1) 共享/排它锁(Shared and Exclusive Locks)
共享锁和排他锁是InnoDB引擎实现的标准行级别锁。
拿共享锁是为了让当前事务去读一行数据。
拿排他锁是为了让当前事务去修改或删除某一行数据。。
设置共享锁:select * from user where id = 1 LOCK IN SHARE MODE;
设置排他锁:select * from user where id = 1 FOR UPDATE;
(2) 意向锁(Intention Locks)
意向锁存在的意义在于,使得行锁和表锁能够共存。
意向锁是表级别的锁,用来说明事务稍后会对表中的数据行加哪种类型的锁(共享锁或独占锁)。
当一个事务对表加了意向排他锁时,另外一个事务在加锁前就会通过该表的意向排他锁知道前面已经有事务在对该表进行独占操作,从而等待。
为什么没有意向锁的话,表锁和行锁不能共存?
举个粟子(此时假设行锁和表锁能共存): 事务A锁住表中的一行(写锁)。事务B锁住整个表(写锁)。
但你就会发现一个很明显的问题,事务A既然锁住了某一行,其他事务就不可能修改这一行。这与”事务B锁住整个表就能修改表中的任意一行“形成了冲突。所以,没有意向锁的时候,行锁与表锁共存就会存在问题!
意向锁是如何让表锁和行锁共存的?
有了意向锁之后,前面例子中的事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞。
所以,意向锁的作用就是:
当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。
说明:意向锁之间都是兼容的,之前是我看错了,Im so sorry参考:https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-intention-locks
意向锁是表锁还是行锁?
首先可以肯定的是,意向锁是表级别锁。意向锁是表锁是有原因的。
当我们需要给一个加表锁的时候,我们需要根据意向锁去判断表中有没有数据行被锁定,以确定是否能加成功。如果意向锁是行锁,那么我们就得遍历表中所有数据行来判断。如果意向锁是表锁,则我们直接判断一次就知道表中是否有数据行被锁定了。
(3) 记录锁(Record Locks)
记录锁是索引记录上的锁,例如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;会阻止其他事务对c1=10的数据行进行插入、更新、删除等操作。
记录锁总是锁定索引记录。如果一个表没有定义索引,那么就会去锁定隐式的“聚集索引”。
(4) 间隙锁(Gap Locks)
间隙锁是一个在索引记录之间的间隙上的锁。
一个间隙可能跨越单个索引值、多个索引值,甚至为空。
对于使用唯一索引 来搜索唯一行的语句,只加记录锁不加间隙锁(这并不包括组合唯一索引)。
(5) 临键锁(Next-key Locks)
Next-Key Locks是行锁与间隙锁的组合。当InnoDB扫描索引记录的时候,会首先对选中的索引记录加上记录锁(Record Lock),然后再对索引记录两边的间隙加上间隙锁(Gap Lock)。
(6) 插入意向锁(Insert Intention Locks)
插入意向锁是在数据行插入之前通过插入操作设置的间隙锁定类型。
如果多个事务插入到相同的索引间隙中,如果它们不在间隙中的相同位置插入,则无需等待其他事务。例如:在4和7的索引间隙之间两个事务分别插入5和6,则两个事务不会发冲突阻塞。
(7) 自增锁(Auto-inc Locks)
自增锁是事务插入到有自增列的表中而获得的一种特殊的表级锁。如果一个事务正在向表中插入值,那么任何其他事务都必须等待,保证第一个事务插入的行是连续的自增值。
二、锁的实现方式
InnoDB行锁是通过给索引加锁来实现的,如果没有索引,InnoDB会通过隐藏的聚簇索引来对记录进行加锁(全表扫描,也就是表锁)。
但是,为了效率考量,MySQL做了优化,对于不满足条件的记录,会放锁,最终持有的,是满足条件的记录上的锁。但是不满足条件的记录上的加锁/放锁动作是不会省略的。所以在没有索引时,不满足条件的数据行会有加锁又放锁的耗时过程。
索引分为主键索引和非主键索引两种。如果一条sql语句操作了主键索引,MySQL就会锁定对应主键索引;如果一条语句操作了非主键索引,MySQL会先锁定非主键索引,再锁定对应的主键索引。
三、mysql锁在4种事务隔离级别里的应用
事务的四种隔离级别有:
- 读未提交(Read Uncommitted)
此时select语句不加任何锁。此时并发最高,但会产生脏读。 - 读提交(Read Committed, RC)
普通select语句是快照读
update语句、delete语句、显示加锁的select语句(select … in share mode 或者 select … for update) 等,除了在外键约束检查和重复键检查时会封锁区间,其他情况都只使用记录锁; - 可重复读(Repeated Read, RR)
普通select语句也是快照读
update语句、delete语句、显示加锁的select语句(select … in share mode 或者 select … for update)则要分情况:- 在唯一索引上使用唯一的查询条件,则使用记录锁。如: select * from user where id = 1;其中id建立了唯一索引。
- 在唯一索引上使用 范围查询条件,则使用间隙锁与临键锁。如: select * from user where id >20;
- 串行化(Serializable)
此时所有select语句都会被隐式加锁:select … in share mode.
四、快照读、当前读
要理解前面四种隔离级别的加锁方式,对于MVCC、快照读、当前读 都是必须要理解的。
MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
什么是多版本并发控制(MVCC:multi-version concurrency control )
MVCC定义:多版并发控制系统。可认为是行级锁的一个变种,它能够避免更多情况下的加锁操作。
作用:避免一些加锁操作,提升并发性能。
实现:通过在每行记录的后面保存行的创建时间和过期时间或删除时间(它们是隐藏的),这两个时间实际都是系统的版本号。每开始一个新的事务,版本号都会自动增加。
具体原理
4.1) select:innoBD查询时会检查以下两个条件:一个是数据行的版本号早于当前事务的版本号;另一个是行的删除版本号,要么没有,要么大于当前事务的版本号。4.2)insert/delete:innoDB将当前的系统版本号作为新插入(删除)的数据行的版本号。
4.3)update:先新插入一行数据,并将当前系统版本号作为行的版本号,同时将当前系统版本号作为原来行的删除版本号。更新主键时,聚集索引和普通索引都会产生两个版本;而更新非主键时,只要普通索引会产生两个版本。
注意:MVCC只在read committed和repeatable read两个隔离级别下工作。
[参考:《高性能mysql》]
快 照 读 是 哪 些
一个正常的select…语句就是快照读。
快照读,使得在RR(repeatable read)级别下一个普通select...语句也能做到可重复读。即前面MVCC里提到的利用可见版本来保证数据的一致性。
当 前 读 是 哪 些
insert语句、update语句、delete语句、显示加锁的select语句(select… LOCK IN SHARE MODE、select… FOR UPDATE)是当前读。
为什么insert、update、delete语句都属于当前读?
这是因为这些语句在执行时,都会执行一个读取当前数据最新版本的过程。
当前读的SQL语句,InnoDB是逐条与MySQL Server交互的。即先对一条满足条件的记录加锁后,再返回给MySQL Server,当MySQL Server做完DML操作后,再对下一条数据加锁并处理。
mysql锁相关讲解及其应用的更多相关文章
- mysql 锁相关的视图(未整理)
mysql 锁相关的视图 查看事务,以及事务对应的线程ID 如果发生堵塞.死锁等可以执行kill 线程ID 杀死线程 kill 199 SELECT * FROM informat ...
- CAS锁相关讲解
感谢GOOGLE强大的搜索,借此挖苦下百度,依靠百度什么都学习不到! 参考文档: http://www.blogjava.net/xylz/archive/2010/07/04/325206.html ...
- MySQL锁之二:锁相关的配置参数
锁相关的配置参数: mysql> SHOW VARIABLES LIKE '%timeout%'; +-----------------------------+----------+ | Va ...
- mysql配置的讲解 mysql的root密码重置 mysql的登录
一,MySQL配置的讲解 port 默认mysql端口 socket 用于服务器端和客户端通信的套连接文字 skip-locking 取消文件系统的外部锁 key_buffer_size 索引缓 ...
- 小结java自带的跟锁相关的一些类
java.util.concurrent包下的一些跟锁相关的类列表 类 简介 locks.Lock接口 Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作.此 ...
- MySQL锁详细讲解
本文章向大家介绍MySQL锁详细讲解,包括数据库锁基本知识.表锁.表读锁.表写锁.行锁.MVCC.事务的隔离级别.悲观锁.乐观锁.间隙锁GAP.死锁等等,需要的朋友可以参考一下 锁的相关知识又跟存 ...
- MySQL学习笔记-锁相关话题
在事务相关话题中,已经提到事务隔离性依靠锁机制实现的.在本篇中围绕着InnoDB与MyISAM锁机制的不同展开,进而描述锁的实现方式,多种锁的概念,以及死锁产生的原因. Mysql常用存储引擎的锁 ...
- MySQL MEM_ROOT详细讲解
这篇文章会详细解说MySQL中使用非常广泛的MEM_ROOT的结构体,同时省去debug部分的信息,仅分析正常情况下,mysql中使用MEM_ROOT来做内存分配的部分. 在具体分析之前我们先例举在该 ...
- Mysql学习总结(10)——MySql触发器使用讲解
触发器(TRIGGER)是由事件来触发某个操作.这些事件包括INSERT语句.UPDATE语句和DELETE语句.当数据库系统执行这些事件时,就会激活触发器执行相应的操作.MySQL从5.0.2版本开 ...
随机推荐
- pip 安装使用 ImportError: No module named setuptools 解决方法
安装过程详见这篇博客: http://www.ttlsa.com/python/how-to-install-and-use-pip-ttlsa/ 安装后运行到:python setup.py ins ...
- LeetCode 重排链表 OPPO笔试
重排链表 几个关键点: 1. 双指针(快慢指针找中点)(用于反转后一部分) 2. 反转后一部分 (reverse函数) 3. 合并链表 合并的时候在笔试的时候想了一种比我之前想的简单的方法 从slow ...
- freeswitch APR库
概述 freeswitch依赖库源代码基本都可以在libs目录下找到. 在freeswitch的官方手册中,可以找到freeswitch的依赖库表格,其中freeswitch的core核心代码依赖库主 ...
- [python]Appium+python +pytest 实现APP自动化,基于安卓
1.安卓环境搭建 &关于app自动化,个人觉得安装过程比较复杂,脚本难度实现和web自动化差不多封装关键字即可,因此,下面会写安装.启动APP以及过程中遇到的一些坑(这一篇偏向解释给个人) & ...
- 架构小试之IDL
本文转载自我自己的博客,感兴趣的老爷们可以关注~:https://www.miaoerduo.com/2021/11/16/arch-idl/ 为什么IDL的介绍也放在这里呢?一方面是我想不到放哪里, ...
- 网络带宽和速度测试windows和linux用iperf工具
网络带宽和速度测试windows和linux用iperf工具 Iperf是一个网络性能测试工具.Iperf可以测试TCP和UDP带宽质量.Iperf可以测量最大TCP带宽,具有多种参数和UDP特性 ...
- Maven 源码解析:依赖调解是如何实现的?
系列文章目录(请务必按照顺序阅读): Maven 依赖调解源码解析(一):开篇 Maven 依赖调解源码解析(二):如何调试 Maven 源码和插件源码 Maven 依赖调解源码解析(三):传递依赖, ...
- [hdu4747]Mex
首先计算出以1为左端点的所有区间的mex,考虑删除左端点仍然维护这个序列:设当前删除点下一次出现在y,y~n的mex不变,从左端点到y的点中大于删除值的点要变成删除值,因为这个是不断递增的,所以是一段 ...
- 性能压测-压力测试-Apache JMeter安装使用
http://jmeter.apache.org/download_jmeter.cgi 下载win10得zip文件 在有java环境后进入项目得bin->jmeter.bat 启动 自带国际化 ...
- Codeforces Gym 101221G Metal Processing Plant(2-SAT)
题目链接 题意:有 \(n\) 个元素,第 \(i\) 个数与第 \(j\) 个数之间有一个权值 \(d_{i,j}\),\(d(i,j)=d(j,i)\). 定义函数 \(D(S)=\max\lim ...