在谈 Mysql 事务的时候,提到在可重复读级别下不仅可以解决当前读级别下的幻读问题,还能解决当前读级别下的幻读问题,而解决方案就是使用 Mysql 锁。
要谈 Mysql 锁,需要从两个方向来看,分别是锁的模式和锁的算法,锁的模式可以分为共享锁、排他锁和意向锁。锁的算法也可以称为锁的粒度,可以有记录锁、间隙锁和意向锁等等。
锁模式
- 共享锁(Shared Locks
这是一种读锁,读读之间不互斥,读写之间互斥SELECT语句在可重复读级别下和串行化级别下会自动为其加上 S 锁
除了自动加锁,我们也可以在 Select 语句执行时手动加锁,但是这种做法是不被推荐的,因为有很大的可能会造成死锁,加锁语句:SELECT … LOCK IN SHARE MODE - 排他锁(Exclusive Locks,又称为 X 锁
这是一种写锁,跟其他读、写操作都是相互互斥的
在更新、删除、插入的操作中都会自动的帮我们加上 X 锁
为 SELECT 语句加 X 锁是解决幻读的核心,加锁语句:SELECT … FOR UPDATE - 意向锁(Intention Locks
这是一个表级锁,其用法是:如果我们希望在一个表上加一个表级锁,那么加锁的前提一定是要先确保整个表没有与其互斥的锁,怎么确定?最简单的方式就是将整个表扫描一遍,这将会带来很大的性能开销,所以引入了意向锁:当一个事务试图对一个表添加行级锁时,无论加锁是否成功,都会在表上方再加一个对应意向锁(IX 或者 IS),当令事务试图加表级锁时,就先看这个表上是否有与其互斥的意向锁,有的话就只能通过意向锁撤销后再次加锁,这样就避免了全表扫描。
锁算法
锁算法大都是 InnoDB 的行级锁,在使用时与锁模式结合来使用。
- 记录锁
针对的是索引中的一条实际的真正存在的记录 - 间隙锁
锁住索引中一段开区间,是两个相邻的真实记录之间的一个范围。 - 临键锁
其实就是一个间隙锁的基础上,再为右边的那条真实记录也给加上锁,也就是一个左开右闭的区间;在为范围的 SELECT 语句加锁时,实际上使用的都是临键锁 - 意向插入锁
我们已经知道在指定插入语句的时候会自动加上 X 锁,如果这段范围被加上了临键锁怎么办?就可以使用意向插入锁,这个范围的意向插入锁需要顺序执行,防止后插入的数据生效导致数据不一致。 - 自增锁
这是一个特殊的表级锁。当我们向表中插入数据并且使用了自增主键时就会添加自增锁,自增锁只会与自增锁之间互斥。通过这种方式保证了自增 id 的唯一性。
Comments NOTHING