innodb锁类型
1.1排他锁

排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务获得相同数据集的共享读锁和排他写
锁。即排它锁与排它锁不能一起使用,排它锁与共享锁不能一起使用
左边是事务1,右边是事务2,事务2出现锁等待现象。

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_加锁

对于 update、delete、insert 语句,InnoDB 会自动给设计到的数据集加排他锁即 X。
对于 select 语句,InnoDB 不会加任何锁
1.2共享锁

共享锁(S):共享锁与共享锁可以一起使用

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_mysql_02

2 死锁的产生和处理

指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作
用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为
死锁进程。

死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_mysql共享锁和排他锁的解锁_03

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
还有一种可能不会直接报错,而是事务1在等待事务2 ,事务2在等待事务1,
锁等待的时间 wait_timeout=120 --设置的是锁等待的时间
锁等待时间结束之后会有一个失败和一个成功

2.1死锁的预防

1)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
2)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
3)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择
4) 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

3.乐观锁和悲观锁的解释

悲观锁:简单的说就是悲观。悲观锁不管是加什么锁,只要是上了锁都属于悲观锁
乐观锁:乐观 例如MVVC

3.1MVCC-多版本并发控制实现乐观锁

MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。每个事务读到的数据项都是一个历史快
照,被称为快照读,不同于当前读的是快照读读到的数据可能不是最新的,但是快照隔离能使得在整个事
务看到的数据都是它启动时的数据状态。而写操作不覆盖已有数据项,而是创建一个新的版本,直至所在
事务提交时才变为可见。

当前读

像 select lock in share mode (共享锁), select for update ; update, insert ,delete (排他锁) 这些操作都是一种
当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前
记录,会对读取的记录进行加锁。

快照读

像不加锁的 select 操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是未提交读和串行
化级别,因为未提交读总是读取最新的数据行,而不是符合当前事务版本的数据行。而串行化则会对所有
读取的行都加锁

4.间隙锁与行锁升级为表锁

4.1 什么是间隙锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记
录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加
锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_数据_04

上图可以看到 事务2在执行新增id为2的数据时出现了所等待现象。说明id为2的数据被事务1进行的范围查询加
锁锁住,其他事务需要等到事务1进行提交或者回滚之后 才能继续操作事务1锁住的数据。

4.2 行锁升级为表锁

在不使用索引的情况下加锁

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_mysql_05


通过上图的两个事务可以得知。尽管加锁的数据不同,但事务2中仍然出现了锁等待现象。说明此时事务1从行锁升级为表锁,导致事务2在给age=20的数据加锁时出现了所等待现象。

在使用普通索引的情况进行加锁

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_数据_06


通过上图可以得知,在加了索引后,同样的加锁操作,但事务2中并没有出现锁等待现象。user表也没有进行表锁.那是因为行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁

范围性查询测试

mysql共享锁和排他锁的解锁 innodb共享锁和排他锁_死锁_07


从上图可以得知:当要进行加锁的数据不确定时,也一样会是表锁

综合上面3种情况得出:
1.行锁是建立在索引的基础上。
2.普通索引的数据重复率过高导致索引失效,行锁升级为表锁