内容简介:MySQL是一个支持插件式存储引擎的数据库系统,其中InnoDB是MySQL的事务安全的存储引擎,在OLTP系统中使用非常广乏。InnoDB最大的特性是支持事务,事务的特性包括原子性、一致性、隔离性、持久性,其中事务的隔离性,就是通过锁来实现的。在正式介绍锁之前,先来回顾一下MySql/InnoDB的隔离级别:InnoDB存储引擎有两种行级锁他们的兼容性如下:
背景
MySQL是一个支持插件式存储引擎的数据库系统,其中InnoDB是 MySQL 的事务安全的存储引擎,在OLTP系统中使用非常广乏。InnoDB最大的特性是支持事务,事务的特性包括原子性、一致性、隔离性、持久性,其中事务的隔离性,就是通过锁来实现的。在正式介绍锁之前,先来回顾一下MySql/InnoDB的隔离级别:
-
READ UNCOMMITTED 可以读取到未提交的数据,会产生脏读的问题
-
REA D COMMITTED 读取已经提交的数据,不会有脏读,但是会有不可重复读和幻读。
-
REPEATABLE READ 在同一个事务 中,可以重复读取,同时InnoDB在此隔离级别下不会有幻象读现象。
-
SERIALIZABLE 读取和写入都需要加锁,效率比较低。
锁的类型
InnoDB存储引擎有两种行级锁
-
共享锁 S,允许事务读取一行数据。
-
排他锁 X,允许事务修改一行数据。
他们的兼容性如下:
| 兼容性 | X | S |
|---|---|---|
| X | 不兼容 | 不兼容 |
| S | 不兼容 | 兼容 |
除此之外,InnoDB还有一种表级别锁,意向锁:
-
意向共享锁 IS,表示事务想要获取表中某几行的共享锁。
-
意向排他锁 IX,表示事务想要获取表中某几行的排他锁。
InnoDB的意向锁主要用户多粒度的锁并存的情况。比如事务A要在一个表上加S锁,如果表中的一行已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念。举个例子,如果表中记录1亿,事务A把其中有几条记录上了行锁了,这时事务B需要给这个表加表级锁,如果没有意向锁的话,那就要去表中查找这一亿条记录是否上锁了。如果存在意向锁,那么假如事务A在更新一条记录之前,先加意向锁,再加X锁,事务B先检查该表上是否存在意向锁,存在的意向锁是否与自己准备加的锁冲突,如果有冲突,则等待直到事务A释放,而无须逐条记录去检测。事务B更新表时,其实无须知道到底哪一行被锁了,它只要知道反正有一行被锁了就行了。
说白了意向锁的主要作用是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”。
读取
innoDB中的数据读取分为锁定读取和非锁定读取。
非锁定读取
非锁定读指的是在读取的时候不需要加任何锁,读写不冲突。对于简单的查询语句select * from table where ?;在离级别READ UNCOMMITTED,READ COMMITTED和REPEATABLE READ下,是非锁定读取。在隔离级别SERIALIZABLE下,是锁定读取,需要获取行锁,此隔离级别效率极低,线上都不会采用。
在读多写少的OLTP系统当中,非锁定读取可以极大提高系统的并发处理能力。innoDB通过多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)来实现非锁定读取,在读取的时候不用等待行上的锁释放,直接去读取行的一个快照数据。流程如下图所示:
对于行上的快照数据,innoDB是通过undo log来实现的,undo log可用于回滚事务,也可以用来实现MVCC功能。一个行上可能不只有一个版本的快照数据,对于事务隔离级别READ COMMITTED和REPEATABLE READ,他们所读取的快照版本是不一样的。在READ COMMITTED下,读取的快照数据总是最新的版本,在REPEATABLE READ下,总是读取事务开始时的行数据。
锁定读取
在某些情况下,为了保证数据的一致性,要先获取行锁,再进行数据读取。如下所示语句都会产生锁定读取:
-
select ... lock in share mode; S
-
select ... for update; X
-
insert into table values (..); 由于插入时需要唯一性检查,所以需要X锁。
-
update table set ? where ?; X
-
delete from table where ?; X
行锁的算法
-
Record Lock:单个行记录上锁。
-
Gap Lock:间隙锁,锁定一个范围,不包含记录本身。
-
Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。
Record lock单条索引记录上加锁,Record lock锁住的永远是索引,而非记录本身。索引分为主键索引和非主键索引两种,如果一条 sql 语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。即使该表上没有任何索引,那么innodb会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁。
Gap Lock锁定的是索引之间的间隙,并不是记录本身。例如有一个索引有3,5,6,10和20这几个值,他们之前的间隙包括(-∞,3)、(3,5)、(5,6)、(10,20)、(20,+∞),对于Gap Lock锁定就是这几个范围。
InnoDB在不同的隔离级别下使用的锁算法也不同。
READ COMMITTED
对于innoDB的READ COMMITTED隔离级别下,会存在幻象读问题。在该隔离级别下,除了外键约束和唯一性检查依然需要Gap Lock,其余情况均使用Record Lock进行锁定。
REPEATABLE READ
InnoDB在该隔离级别下,没有幻读现象。幻读是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次执行可能返回之前不存在的行。例如对下述语句:select * from table where id > 10 for update; 在事务1查询之后,如果另一个事务2可以插入id大于10的记录,在事务1下次查询的时候也会返回事务2插入的记录,两次的读取结果不一样,这就是幻读。
InnoDB通过Next-key Lock来避免幻读的现象,除了锁住记录本身之外,还要锁住可能涉及到的间隙(Gap)。对于上述例子select * from table where id > 10 for update; 在REPEATABLE READ隔离级别下锁定是(10,+∞)这个范围。
总结
本文主要介绍了InnoDB的锁的类型及RC和RR级别下的加锁情况,希望能给大家带来帮助。
以上所述就是小编给大家介绍的《InnoDB 锁原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- java反射原理, 注解原理
- Webpack 原理(二):加载原理
- Docker原理之 - CGroup实现原理
- 【Vue原理】响应式原理 - 白话版
- Docker实现原理之 - OverlayFS实现原理
- UAV MOF工作原理之Agent注入机制原理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Mechanics of Web Handling
David R. Roisum
This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!