数据库事务3(mvcc与innodb锁机制)

带着问题思考。

Q:
读写,写写冲突,或者说基本的dml操作 insert,update,delete,select,innodb存储引擎是如何处理的(在默认隔离级别repeatable-read)?

为什么insert ignore 和 update on duplicate key 会造成死锁? 在什么情况下会造成死锁,如何解决?

不同隔离级别的dml的加锁策略有什么区别?

S和IX锁是互斥的吗?

意向锁和插入意向锁的联系与不同。

什么时候innodb会加表锁?(默认rr隔离级别)

两阶段加锁?

在阐述crud操作会涉及到那些操作时,首先需要了解一些锁,同时没有特别强调的话,默认讨论的是rr级别下的情况。

虽然本章讨论的是innodb加锁的情况,但还是要联系mvcc的内容。常见的 “select * from xx” 会加锁吗?select * 是全表扫描,但是此select还是会基于生成的readview,读取快照内容,所以不会阻塞 读&写,更别提加锁了。没有特殊需求直接select的话,我们用户用的查询是会走快照读的,不会锁行也不会锁表,这也是为什么innodb值得学习。

表锁,行锁(间隙锁) 多的不说了,锁级别就是加在不同对象上的锁,表锁就是锁一张表,行锁就是锁一行,值得说的是间隙锁,会锁住多行连续(按索引算连续)数据。

独占锁和共享锁好理解,可以基本认为是常见的读写锁,类似于java中的ReentrantReadWriteLock,作用也是类似。 但实际上来说有一点特别的是并非读(select)只能加共享锁,select也可以加X锁。 手动加锁的查询有一下两种方式: select * from xx for share select * from xx for update

意向锁需要好好唠叨一下。 按是否独占可分为:独占意向锁IX,共享意向锁IS 按名字可以简单猜测,意向锁就是表明意向,所以意向锁之间不是互斥的,对同一资源的加锁不会阻塞(事实也确实如此)。
在innodb中意向锁是表级锁(这个很重要,区分插入意向锁),是行级锁和表级锁的桥梁。为什么这么说?没有意向锁的情况下,如果要加表X锁,是不是需要查看有没有在行(或间隙)上加的锁(S或X),如果要对表加S锁,是不是需要查看有没有在行(或间隙)上加的X锁。这个判断的过程需要是原子的,且遍历的过程是需要耗时的,所以可以具象化冲突(详见ddia事务章节),在数据库表上构建出IX,IS这两种意向锁。每次对行(间隙)加锁前都先对表加上意向锁,这样如果需要加表锁,就可以仅查看此表上有没有表锁冲突,而不需要查看子对象(行)上是否有冲突。

总结来说X,S,IX,IS之间的互斥关系为

- X S IX IS
X × × × ×
S × ×
IX × ×
IS ×

特别的 1、IX和S锁是互斥的,简单理解下,在已经有共享表锁的情况下,如果需要对某行进行独占锁定,需要等待共享表锁释放。 举个栗子,我现在(select * from xx for share)查询整张表或者where没有命中索引,于此同时修改/删除(todo插入不清楚)某条数据,是不是我的写操作要等全表扫描结束?是的。 2、意向锁是表级锁 3、意向锁之间不会阻塞

当事务中出现update等写操作需要读取当前的最新的已提交数据,且为了保证不发生写写的冲突(与其他事务的更新冲突),需要锁定一系列的

当一个事务想要插入数据时,他需要检测当前行是否被