MySQL中的锁介绍和使用

北京中科 https://wapjbk.39.net/yiyuanzaixian/bjzkbdfyy/etbdf/

所有普通的select语句在已提交读、可重复读的隔离级别下都是一致性读,也就是使用MVCC进行的读取操作。而在有些场景下,如果只允许读取记录的最新版本,我们就需要加锁。使用MVCC的话,读-写操作并不冲突,而使用加锁操作的话,读-写操作需要排队执行。

排它锁(ExclusiveLock)/X锁:事务对数据加上X锁时,只允许此事务读取和修改此数据,并且其它事务不能对该数据加任何锁;共享锁(SharedLock)/S锁:加了S锁后,该事务只能对数据进行读取而不能修改,并且其它事务只能加S锁,不能加X锁

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X锁);对于普通SELECT语句,InnoDB不会加任何锁(使用MVCC);事务可以通过以下语句显式给记录集加共享锁或排他锁:

共享锁(S锁):SELECT*FROMtable_nameWHERE...LOCKINSHAREMODE排他锁(X锁):SELECT*FROMtable_nameWHERE...FORUPDATE

锁有不同的粒度,可以分为行级锁和表级锁。那么如果想对一个表加X锁,这个时候如果还需要先检测是否有其它事务对该表或者该表中的某一行加了锁,这样效率就太低了,因此InnoDB还提出了一个意向锁(IntentionLocks)的概念:

一个事务在获得某个数据行对象的S锁之前,必须先获得整个表的IS锁或更强的锁;一个事务在获得某个数据行对象的X锁之前,必须先获得整个表的IX锁;IS/IX锁之间都是兼容的;InnoDB中的行级锁

在InnoDB中,行级锁也有很多不同的类型,用于不同的加锁场景:

RecordLocks:就叫记录锁吧,也就是锁住一条记录,分为X型记录锁和S型记录锁,作用和上面提到的X锁和S锁类似GapLocks:就叫间隙锁吧。给一条记录加上间隙锁意味着不允许在这条记录前面的间隙插入新记录,它的作用就是防止插入幻影记录,防止出现幻读。

间隙锁是加在记录前面的间隙的,那么如何防止别的事务在最后一条记录的后面插入幻影记录呢?其实只需要在页面的Supremum记录(表示该页面中最大的记录)上加一个间隙锁就行了。

Next-KeyLocks:记录锁和间隙锁的结合,既锁住了一条记录,也锁住了记录前面的间隙InsertIntentionLocks:插入意向锁。当一个事务想要插入一条记录的时候,如果要插入的位置上已经被加了间隙锁,那么该事务就会生成一个插入意向锁并处于等待状态。等到间隙锁释放之后,该事务就能获取到插入意向锁了。插入意向锁之间互不阻塞,插入意向锁也不会阻止别的事务获取该记录上任何类型的锁。隐式锁:如果一个事务刚插入一条新记录(此时这条记录上还没有任何锁结构),这时另一个事务想要获取该记录的X锁或者S锁,该怎么办,岂不是会产生脏读或者脏写问题?其实,虽然这条新记录上没有任何锁结构,但在聚簇索引的记录上有一个trx_id隐藏列,另一个事务会先判断trx_id是否是当前的活跃事务,如果是,则会自动帮助当前事务创建一个X锁,然后自己的锁进入等待状态。相当于对新插入的记录加了一个隐式锁。InnoDB锁的内存结构

其中行锁信息中的n_bit是表示使用了多少比特位,用于和后面的“一堆比特位”用来定位页面中的具体记录,算法比较trick这里略过。

type_mode被分成了lock_mode、lock_type和rec_lock_type三个部分(还有一个比特位用来表示is_waiting,即是否在等待状态)。lock_mode用来表示是X锁、S锁、IS锁等等类型。lock_type用来表示是行级锁还是表级锁。rec_lock_type则用来表示在行级锁的情况下,具体的锁类型,比如间隙锁。




转载请注明:http://www.aierlanlan.com/tzrz/8372.html

  • 上一篇文章:
  •   
  • 下一篇文章: