Innodb引擎里面的锁
Innodb引擎里面的锁
Lock和Latch
lock和latch是两种不一样的东西,在mysql里面都有使用,lock锁的是事务,latch锁的是线程间的共享数据。
锁的分类
锁最基础的分类就是共享锁和排它锁了
共享锁:S锁,可理解为读锁 排它锁:X锁,可理解为死锁
表级锁
意向锁
意向锁是什么
意向锁表达的是,对这个表有锁定的意向,并没有实际的上锁,它只对全表扫描的操作有阻塞作用。
意向锁也分为IX-IS,也就是共享锁和排它锁
意向锁有什么用
意向锁的用途就在于全表扫描的时候。
假设有如下场景:
我需要去全表扫描select * from t1 但是我不知道表里面有没有S锁锁住了记录怎么办 方案1:我一个个去查,有锁我就等等他 方案2:我对一个行加行X锁的时候,顺手给表加了个IX锁,这样当要全表扫描的时候,人家就知道现在不能扫描了,乖乖阻塞住。
很明显方案2听起来很靠谱,方案1太鸡肋了,这也就是意向锁的用途。
自增锁
自增锁是什么
在给主键赋予了自增属性(假设为id)的时候,那对于这个id的获取,那肯定是不能乱来的。所以派生出了AUTOINC_LOCK
自增锁有什么用
在insert的时候会去获取这么一个表级的锁,别人等我插入完了你再插入咯。这样可以保证id正确的被获取
自增锁太慢了!我想快点
innodb里面提供了一个参数innodb_autoinc_lock_mode,参数值有:
0:代表现在使用的是AUTOINC锁 1:代表这是自适应的方式,如果是simple insert那就用快一点的方式,如果是bulk insert,一堆给我干过来,那就使用AUTOINC锁。 2:代表现在使用的是一个“快一点的方式"。
什么是快一点的方式
innodb自己也觉得AUTOINC有时候太慢了,所以它提供了一个获取完id就可以释放锁了的操作,只对id这么一个共享变量进行一个互斥的读取。
出现问题了-binlog-主从复制
当然欲速则不达,这种方式就出问题了,当出现并发insert的时候,就可能会出现问题。
场景如下:
A事务下想对表t插入一条数据,它获取了id为2. insert into t values(2, "我是A") B事务下想对表t插入一条数据,它获取了id为3. insert into t values(3, "我是B") 但是但是但是,他们真实插入的时候,可能B比A更快。 如果此时好巧不巧,我就使用了statement的binlog_format,那么在复制的时候,到从表就变成了(3, "我是A"),(2,"我是B")这么两条数据了。出现了主从不一致的可怕问题。
所以说这种方式有局限性-那么就是只能使用raw的binlog_format.
行级锁
Record Lock
Gap Lock
Gap Lock是什么
Gap Lock有什么用
GapLock听得最多的就是防止幻读。
场景如下:
假设现在是select * from t1 where id > 3 那么现在另一个事务里插入了一条 insert into t1 values(4, "幻读来咯") 我再次执行select * from t1 where id > 3,会发现我眼花了,多读出一条记录了。 如果我现在给我此时的事务中加一个GapLock,那另一个事务里的插入就会被阻塞,那么幻读就会被拒绝。
GapLock出现在RR下,RC没有
那么这就也可以说明,RR下是会出现幻读的。
GapLock之间是不会被阻塞的,它的作用只是让别人别过来再写了
Next-Key Lock
Next-Key Lock是什么
他是GapLock+Record的组合,可以说是把当前记录和间隙都锁住了。
Next-Key Lock有什么用
它的作用就是支持不需要使用不可重复读和幻读的场景
当你查询的where的东西是一个唯一的值,那就会被降级成record lock
Next-Key Lock之间是会相互阻塞的。
多粒度锁
Innodb中是支持多粒度锁的,也就是说行锁和表锁同时存在,其实也就是意向锁干的,这里只是单独列出来说明。
MVCC-多版本并行控制
MVCC是什么
MVCC干了什么
它做的就是如果有写锁占住了一个record,这时候如果我想要去读它就要一直等,那么我现在想不让他等,就直接去读快照咯。
一致性非锁定读的原理-undo log
原理就是在于undo log,我们读取的时候,去读已经生成的之前版本的快照是肯定不用上锁的,毕竟已经没人会去再修改它了。
不同事务隔离级别的MVCC
RR
RC
一致性非锁定读其实不保证数据一致性
它只是为了让读的时候更快的一种操作,如果你不想出现幻读和不可重复读,那就乖乖上锁,上锁以后就关乎于之前提到的行级锁啦。
SELECT ... FOR UPDATE-加X锁 SELECT ... LOCK IN SHARE MODE-加S锁
脏读、幻读、不可重复读
脏读-问题!
解决办法
脏读的解决办法比较简单,将事务隔离级别提到RC就行了,脏读就是出现在Read UnCommited
幻读
幻读其实不是一个问题,而是一个现象。在一些数据库默认级别为RC的厂商眼里,他们都是允许这个的发送的。
幻读就是一个事务内,两次读出来的数量不同
解决办法
不可重复读
不可重复读和幻读类似,它是出现在读的本条数据上,它被人修改掉了,两次读的数据的内容不一致。
解决办法同幻读。
死锁
既然上锁,那肯定会出现死锁,很正常,一是要正确操作避免死锁,二是要死锁发送破坏死锁。
为什么会死锁
当A事务已经给data1上锁,B事务已经给data2上锁,此时A事务想要操作data2,而B事务想要操作data1,完蛋咯,出现死锁
怎么破坏死锁
innodb下是使用了wait-for-graph对死锁的检查。他会去用dfs检查有无环存在(个人想到了spfa哈哈哈哈),如果有死锁就会选择回滚undo log最少的那个事务去破坏死锁。