mysql锁机制 -高频面试题必知必会系列
2022-02-16 14:55:16 12 举报
AI智能生成
登录查看完整内容
架构师必知必会系列-mysql锁机制
作者其他创作
大纲/内容
事务想要获取一张表中某几行的共享锁
意向共享锁(Intention S Lock)
意向锁
共享锁(S Lock)
事务想要获取一张表中某几行的排他锁
意向排他锁(Intention X Lock)
排他锁(X Lock)
行级锁
指的是innoDB存储引擎通过多版本控制(MVCC)的方式来读取当前执行时间数据库中的行的数据。
如果读取的行正在执行DELETE或UPDTE操作,这时读取操作不会因此去等待行上锁的释放。相反的,InnoDB存储引擎回去读取行的一个快照数据。
之所以称为非锁定读,因为不需要等待访问的行上X锁的释放。快照数据是指该行的之前版本的数据,该实现是通过undo段来完成的。而undo用来在事务中回滚数据,因此快照数据本身是没有额外的开销。此外,读取快照数据是不需要上锁的,因为没有事务需啊哟对历史的数据进行修改操作,
定义
InnoDB存储引擎中默认采用一致性非锁定读。但是不同隔离级别读取方式不同。并不是每个事务隔离级别都是采用非锁定的一致性读。即使都是使用非锁定的一致性读,但是对于快照数据的定义也各不相同。
1、快照数据是当前行数据之前的历史版本,每行记录可能有多个版本。
快照数据概述
非锁定的一致性读
锁方案
总是读取被锁定行的最新一份快照数据。
快照定义
子主题
读已提交,总是读取行的最新版本。
读已提交
可重复读,总是读取事务开始时的数据行。
可重复读
注意,这个时候读已提交和可重复读的差别就出来了
session-1
案例分析
READ COMMITTED
总是读取事务开始时的行数据版本
REPEATABLE READInnoDB默认的隔离级别
事务时间线
按照时间线展示一下过程特别说明下:对于 READ COMMITTED这种事务隔离级别,从数据库理论看,其违反了ACID的I的特性,即隔离性。
各种隔离级别的实现方案
如何实现
一致性非锁定读consistent nonlocking read
InnoDB的默认隔离级别是可重复读,可重复读的实现方案是MVCC的非锁定的一致性读。但是,特殊情况下,用户显示的对数据库读取操作进行加锁以保证数据逻辑的一致性。而这要求数据库支持加锁语句,即使是 SELECT 操作。
session-2
SELECT ... FOR UPDATE会对读取的行加 X 锁(排他锁)。意味着其他事务不能对已锁定的行加上任何锁。
SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE 会对读取的行加 S 锁(共享锁)。意味着其他事务可以对读取的行记录加上一个 S锁,但是如果加 X 锁,则会被阻塞。
SELECT ... LOCK IN SHARE MODE
InnoDB对于SELECT 语句支持李鞥中一致性的锁定读操作
背景
一致性锁定读consistent locking read
有哪些锁?
比对图
在数据库中,lock与latch都可以称之为“锁”,但两者截然不同
线程的临界资源在InnoDB存储引擎中,latch又可以分为mutex(互斥量)和 rwlock(读写锁)。
latch
lock的对象时事务,用来锁定的是数据库中的对象,如表、页、行。
lock
锁定的对象
一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差。
整个事务过程。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。
锁定的时间
其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
lock,正如在大多数数据库一样,是有死锁机制的。
死锁检测机制
搞清锁的概念
InnoDB存储引擎表的索引,如果没有任何一个索引,则会使用隐式的主键来进行锁定
索引从哪里来?
Record Lock总是会去锁住索引记录
Record Lock单个行记录上的锁
A place in an InnoDB index data structure where new values could be inserted.说白了gap就是索引树中插入新记录的空隙。相应的gap lock就是加在gap上的锁,还有一个next-key锁,是记录+记录前面的gap的组合的锁。
什么是Gap Lock?
http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
简单讲就是防止幻读。通过锁阻止特定条件的新记录的插入,因为插入时也要获取gap锁(Insert Intention Locks)。
Gap Lock的作用?
REPEATABLE READ
SESSION 1:SESSION 1中更新id=20的记录,但是不提交。
插入数据测试
对于更新操作,仅20这条记录不能更新,因为更新操作不会去获取gap锁。
更新数据测试
如果SESSION 1的表扫描没有用到索引,那么gap或next-key锁住的范围是整个表,即任何值都不能插入。
特别注意!!!
测试目的
REPEATABLE READ可重复读时gap lock现象
只会锁住已有记录,不会加gap锁。
READ COMMITTED可重复读时gap lock现象
和REPEATABLE READ的主要区别在于把普通的SELECT变成SELECT … LOCK IN SHARE MODE,即对普通的select都会获取gap锁或next-key锁。
SERIALIZABLE可重复读时gap lock现象
准备测试数据:select * from tb2;mysql> select * from tb2;+------+------+| id | c1 |+------+------+| 10 | 0 || 20 | 0 || 30 | 0 |+------+------+3 rows in set (0.01 sec)
测试表
locking reads,UPDATE和DELETE时,除了对唯一索引的唯一搜索外都会获取gap锁或next-key锁。即锁住其扫描的范围。
什么情况下取得Gap Lock?
Gap Lock间隙锁,锁定一个范围,但不包含记录本身https://www.cnblogs.com/diegodu/p/9239200.html
Next-Key Lock= Gap Lock + Record Lock 锁定一个范围,并且锁定记录本身
InnoDB行锁的三种算法
锁的算法
锁
InnoDB存储引擎
事务是逻辑上的一组操作,要么都执行,要么都不执行。
分支主题
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
举个例子
什么是事务?
事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
原子性
执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
一致性
并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
隔离性
一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
持久性
事务的特性ACID
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
带来的问题
当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
脏读(Dirty read)
问题一
指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
丢失修改(Lost to modify)
问题二
指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
不可重复读(Unrepeatableread)
问题三
幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
幻读(Phantom read)
问题四
不可重复读案例
幻读案例
不可重复读的重点是修改。幻读的重点在于新增或者删除。
不可重复度和幻读区别:
并发事务带来的问题
最低的隔离级别,允许读取尚未提交的数据变更
可能会导致脏读、幻读或不可重复读
存在的问题
READ-UNCOMMITTED(读取未提交)
允许读取并发事务已经提交的数据
可以阻止脏读
可以解决的问题
,但是幻读或不可重复读仍有可能发生
READ-COMMITTED(读取已提交)
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
可以阻止脏读和不可重复读
,但幻读仍有可能发生
REPEATABLE-READ(可重复读)
最高的隔离级别,完全服从ACID的隔离级别
所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。
SERIALIZABLE(可串行化)
SQL 标准定义了四个隔离级别
我们可以通过`SELECT @@tx_isolation;`命令来查看,MySQL 8.0 该命令改为`SELECT @@transaction_isolation;`mysql> SELECT @@tx_isolation;+-----------------+| @@tx_isolation |+-----------------+| REPEATABLE-READ |+-----------------+
需要应用使用加锁读来保证。而这个加锁度使用到的机制就是 Next-Key Locks。
MVCC我知道,但是为什么要设计间隙锁?https://www.jianshu.com/p/fbec6d1fa16c
扩展阅读
如何解决?
MySQL InnoDB 的 REPEATABLE-READ(可重读)并不保证避免幻读
MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 **READ-COMMITTED(读取提交内容)** ,但是你要知道的是 InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)** 并不会有任何性能损失。
InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到 **SERIALIZABLE(可串行化)** 隔离级别。
InnoDB 存储引擎提供了对 XA 事务的支持,并通过 XA 事务来支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源(transactional resources)参与到一个全局的事务中。事务资源通常是关系型数据库系统,但也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对于事务原有的 ACID 要求又有了提高。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为 SERIALIZABLE。
拓展一下(以下内容摘自《MySQL 技术内幕:InnoDB 存储引擎(第 2 版)》7.7 章):
扩展
MySQL
防止幻读(可重复读)
在下面我会使用 2 个命令行mysql ,模拟多线程(多事务)对同一份数据的脏读问题。
MySQL 命令行的默认配置中事务都是自动提交的,即执行SQL语句后就会马上执行 COMMIT 操作。如果要显式地开启一个事务需要使用命令:`START TARNSACTION`。
我们可以通过下面的命令来设置隔离级别。SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
transaction_isolation作为tx_isolation的别名被引入,都可用来表示隔离级别
5.7.20版本前
transaction_isolation作为tx_isolation的别名被引入
5.7.20版本后(含)
tx_isolation被废弃,只能使用transaction_isolation
8.0版本后(含)
版本差异
设置隔离级别
我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:
- - `START TARNSACTION` |`BEGIN`:显式地开启一个事务。- - COMMIT`:提交事务,使得对数据库做的所有修改成为永久性。- - `ROLLBACK`:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
事务
show variables like '%version%';
数据库版本
查看
我们可以通过下面的命令来设置隔离级别。SET GLOBAL TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
修改
全局事务级别
我们可以通过下面的命令来设置隔离级别。SET SESSION TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
当前会话隔离级别
show variables like '%isolation%';
事务隔离级别
生产环境
测试环境
数据库隔离级别
背景说明
读未提交(脏读)如何做到的?
避免脏读(读已提交)如何做到的?
还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,session-1事务还没有结束,就发生了 不可重复读问题。
不可重复读如何做到的?
可重复读如何做到的?
间隙锁
间隙锁(Gap Lock)
如何做到的?
防止幻读(串行)如何做到的?
实际情况演示
事务的隔离级别
如何实现的?
常见的问题
事务的原子性
事务的持久性
事务的一致性
mysql锁机制 -高频面试题必知必会系列
![产品全生命周期管理方法论](https://www.processon.com/chart_image/template/thumb/654073d0ba502e52eec7f88d.png?tid=61b315b47d9c08437150e960)
收藏
0 条评论
回复 删除
下一页