概述

锁机制为实现MySQL的各个隔离级别提供了保证,锁冲突也是影响数据库并发访问性能的一个因素

并发问题解决方案

如何解决脏读,不可重复读,幻读这些问题?
1,读操作利用多版本并发控制,写操作进行加锁
普通的select在可重复度和读已提交隔离级别下会使用到MVCC读取记录
(在读已提交隔离级别下,一个事务执行过程中每次select操作都会生成一个readview,readview的存在本身就保证了事务不可以读取到未提交事务所作出的更改,也就避免的脏读现象)
(在可重复读隔离级别下,一个事务只有第一次执行select操作才会产生一个readview,后续都是利用这个readview,也就避免了不可重复度和幻读)

2,读写操作都采用加锁的方式

对比

采用MVCC,读写操作彼此并不冲突,性能更高
采用加锁方式,读写操作彼此需要排队执行,影响性能

锁家族

按对数据的操作类型划分:读锁/共享锁,写锁/排它锁

锁粒度角度划分:

表级锁(表级别的S,X锁,意向锁,自增锁,MDL锁)
行级锁(Record Locks,Gap Locks,Next-Key Locks,插入意向锁)
页级锁

对待锁的态度划分:悲观锁,乐观锁

加锁方式:隐式锁,显示锁

其他:全局锁,死锁

锁的应用

对于innodb来说,读锁和写锁既可以加载表上,也可以加载行上

在执行DML语句时,也有操作进行DDL语句(该操作会被阻塞),innodb引擎会在server层使用一种元数据锁(MDL)

意向锁

image.png
意向锁是由存储引擎自行维护的,用户无法手动操作意向锁,在为数据行加上共享/排他锁之前,innodb会先获取该数据行所在数据表的意向锁

image.png

自增锁

image.png

间隙锁

MySQL在可重复度隔离级别下可以解决幻读问题,1(MVCC),2(加锁)
但是在加锁方案解决时有个问题,事务在第一次执行读取操作时,那些欢迎记录尚不存在,无法给幻影记录上锁,由此innodb提出了一种Gap Locks

临键锁

image.png
MVCC+Next-Key Locks 可防止大部分幻读,但也存在特例
image.png
1.a事务先select,b事务insert确实会加一个gap锁,但是如果b事务commit,这个gap锁就会释放(释放后a事务可以随意操作),
2.a事务再select出来的结果在MVCC下还和第一次select一样,
3.接着a事务不加条件地update,这个update会作用在所有行上(包括b事务新加的),
4.a事务再次select就会出现b事务中的新行,并且这个新行已经被update修改了.
Mysql官方给出的幻读解释是:只要在一个事务中,第二次select多出了row就算幻读, 所以这个场景下,算出现幻读了.

插入意向锁

image.png
插入意向锁并不会阻止别的事务继续获取该记录上任何类型的锁

页锁

image.png

悲观锁与乐观锁

实际上这两种算不上是锁,更多是是一种锁的设计思想

隐式锁和显示锁

隐式锁

image.png
image.png

显示锁

image.png

全局锁

整个库只处于只读状态

锁的内存结构

image.png