金三银四很快就要来啦,准备了数据库锁的12连问,相信大家看完肯定会有帮助的。
1.为什么需要加锁在日常生活中,如果你心情不好想静静,不想被比别人打扰,你就可以把自己关进房间里,并且反锁。这就是生活中的加锁。
同理,对于MySQL数据库来说的话,一般的对象都是一个事务一个事务来说的。所以,如果一个事务内,一个SQL正在更新某条记录,我们肯定不想它被别的事务影响到嘛?因此,数据库设计大叔,给该行数据加上锁(行锁)。
专业一点的说法:如果有多个并发请求存取数据,在数据就可能会产生多个事务同时操作同一行数据。如果并发操作不加控制,不加锁的话,就可能写入了不正确的数据,或者导致读取了不正确的数据,破坏了数据的一致性。因此需要考虑加锁。
2.InnoDB有哪些锁?2.1共享/排他锁
InnoDB呢实现了两种标准的行级锁:共享锁(简称S锁)、排他锁(简称X锁)。
共享锁:简称为S锁,在事务要读取一条记录时,需要先获取该记录的S锁。
排他锁:简称X锁,在事务需要改动一条记录时,需要先获取该记录的X锁。
如果事务T1持有行R的S锁,那么另一个事务T2请求访问这条记录时,会做如下处理:
T2请求S锁立即被允许,结果T1和T2都持有R行的S锁
T2请求X锁不能被立即允许,此操作会阻塞
如果T1持有行R的X锁,那么T2请求R的X、S锁都不能被立即允许,T2必须等待T1释放X锁才可以,因为X锁与任何的锁都不兼容。
S锁和X锁的兼容关系如下图表格:
X锁和S锁是对于行记录来说的话,因此可以称它们为行级锁或者行锁。我们认为行锁的粒度就比较细,其实一个事务也可以在表级别下加锁,对应的,我们称之为表锁。给表加的锁,也是可以分为X锁和S锁的哈。
如果一个事务给表已经加了S锁,则:
别的事务可以继续获得该表的S锁,也可以获得该表中某些记录的S锁。
别的事务不可以继续获得该表的X锁,也不可以获得该表中某些记录的X锁。
如果一个事务给表加了X锁,那么
别的事务不可以获得该表的S锁,也不可以获得该表某些记录的S锁。
别的事务不可以获得该表的X锁,也不可以继续获得该表某些记录的X锁。
2.2意向锁
什么是意向锁呢?意向锁是一种不与行级锁冲突的表级锁。未来的某个时刻,事务可能要加共享或者排它锁时,先提前声明一个意向。注意一下,意向锁,是一个表级别的锁哈。
为什么需要意向锁呢?或者换个通俗的说法,为什么要加共享锁或排他锁时的时候,需要提前声明个意向锁呢呢?
因为InnoDB是支持表锁和行锁共存的,如果一个事务A获取到某一行的排他锁,并未提交,这时候事务B请求获取同一个表的表共享锁。因为共享锁和排他锁是互斥的,因此事务B想对这个表加共享锁时,需要保证没有其他事务持有这个表的表排他锁,同时还要保证没有其他事务持有表中任意一行的排他锁。
然后问题来了,你要保证没有其他事务持有表中任意一行的排他锁的话,去遍历每一行?这样显然是一个效率很差的做法。为了解决这个问题,InnoDb的设计大叔提出了意向锁。
意向锁是如何解决这个问题的呢?我们来看下
意向锁分为两类:
意向共享锁:简称IS锁,当事务准备在某些记录上加S锁时,需要现在表级别加一个IS锁。
意向排他锁:简称IX锁,当事务准备在某条记录上加上X锁时,需要现在表级别加一个IX锁。
比如:
slct...lockinshamod,要给表设置IS锁;
slct...forupdat,要给表设置IX锁;
意向锁又是如何解决这个效率低的问题呢:
如果一个事务A获取到某一行的排他锁,并未提交,这时候表上就有意向排他锁和这一行的排他锁。这时候事务B想要获取这个表的共享锁,此时因为检测到事务A持有了表的意向排他锁,因此事务A必然持有某些行的排他锁,也就是说事务B对表的加锁请求需要阻塞等待,不再需要去检测表的每一行数据是否存在排他锁啦。
意向锁仅仅表明意向的锁,意向锁之间不会互斥,是可以并行的,整体兼容性如下:
2.记录锁(RcordLock)
记录锁是最简单的行锁,仅仅锁住一行。如:SELECTc1FROMtWHEREc1=10FORUPDATE,如果C1字段是主键或者是唯一索引的话,这个SQL会加一个记录锁(RcordLock)
记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。它会阻塞其他事务对这行记录的插入、更新、删除。
一般我们看死锁日志时,都是找关键词,比如lock_modXlockscbutnotgap),就表示一个X型的记录锁。记录锁的关键词就是cbutnotgap。以下就是一个记录锁的日志:
RECORDLOCKSspacid58pagnonbits72indx`PRIMARY`oftabl`tst`.`t`trxidlock_modXlockscbutnotgapRcordlock,hapno2PHYSICALRECORD:n_filds;