十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
因为行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。
目前成都创新互联已为1000多家的企业提供了网站建设、域名、网页空间、网站托管维护、企业网站设计、阳泉网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
间隙锁,锁的就是两个值之间的空隙,不允许两个值之间再插一个值。
比如初始化插入了 6 个记录,这就产生了 7 个间隙。分别是 (-∞,0)、(0,5)、(5,10)、(10,15)、(15,20)、(20, 25)、(25, +supremum),间隙锁都是开区间
和行锁不一样的是,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系。
缺点:可能会导致同样的语句锁住更大的范围,影响了并发度。
间隙锁和行锁合称 next-key lock,每个 next-key lock 是前开后闭区间。如果用 select * from t for update 要把整个表所有记录锁起来,就形成了 7 个 next-key lock,分别是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。
和间隙锁的最大区别是,next-key lock 为前开后闭区间,这样所有的next-key lock就可以把所有记录锁起来。
加锁规则里面,包含了两个“原则”、两个“优化”和一个“bug”
意向锁(Intention Locks; table-level lock)
意向锁是一种特殊的表级锁,意向锁是为了让 InnoDB 多粒度的锁能共存而设计的。取得行的共享锁和排他锁之前需要先取得表的意向共享锁(IS)和意向排他锁(IX),意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预
意向锁就是指未来的某一个时刻事务可能要加共享锁或者排它锁,提前声明一个意向,分为两种:
意向共享锁(Intention Shared Lock) IS
事务有意向对表中的某些行加共享锁(S锁)
意向排它锁(Intention Exclusive Lock)IX
事务有意向对表中的某些行加排他锁(X锁)
记录锁(Record Locks)
官方原文
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 这一行则是使用了记录锁,不允许其他事务进行增,删,改
但是 SELECT c1 FROM t WHERE c1 = 10; 是没有锁的,走的是快照读,上文已经阐明过了
记录锁本身不是锁定记录数据本身而是锁定索引记录,如果要锁的列没有索引,则会进行全表记录加锁
间隙锁(Gap Locks)
官方原文
比如 SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE ;
插入 c1 为 15 的记录会被锁定不可执行
这种默认存在于可重复读的事务隔离级别中的锁,锁定被圈定的范围不允许 insert,防止不可重复读,上文说了我们的事务隔离级别都是读已提交,默认会产生不可重复读的问题
mysql 为并发事务同时对一条记录进行读写时,提出了两种解决方案:
1)使用 mvcc 的方法,实现多事务的并发读写,但是这种读只是“快照读”,一般读的是历史版本数据,还有一种是“当前读”,一般加锁实现“当前读”,或者 insert、update、delete 也是当前读。
2)使用加锁的方法,锁分为共享锁(读锁),排他锁(写锁)
快照读:就是select
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。
mysql 在 RR 级别怎么处理幻读的呢?一般来说,RR 级别通过 mvcc 机制,保证读到低于后面事务的数据。但是 select for update 不会触发 mvcc,它是当前读。如果后面事务插入数据并提交,那么在 RR 级别就会读到插入的数据。所以,mysql 使用 行锁 + gap 锁(简称 next-key 锁)来防止当前读的时候插入。
Gap Lock在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。
Innodb自动使用间隙锁的条件: