锁
事务的隔离性由锁来实现
MySQL并发事务访问相同记录
并发事务访问相同记录的情况大致可以分为3种:
读-读的情况
读-读情况,即并发事务相继读取相同的记录。读取操作本身不会对记录由有任何的影响,并不会引起什么问题,所以允许这种情况的发生。
写-写的情况
写-写情况,即并发事务相继对相同的记录做出改动。
读-写或写-读情况
读-写或写-读,即一个事务进行读取操作,另一个进行改动操作,这种情况下产生脏读、不可重复读、幻读的问题
怎么解决脏读、不可重复读、幻读这些问题呢?其实有两种可选的解决方案:
方案1:读操作利用多版本并发控制(MVCC) ,写操作利用加锁
方案2:读、写操作都采用加锁的方式
锁的不同角度分类
从数据操作的类型划分:读锁、写锁
从数据操作的粒度划分:表级锁、页级锁、行锁
表级锁
意向锁
意向锁要解决的问题
意向锁的并发性
意向锁不会与行级的共享/排他锁互斥!正因为如此,意向锁并不会影响到多个事务对不同数据行加排他锁时的并发性(不然我们直接用普通的表锁就行了)
自增锁(AUTO-INC锁)
元数据锁
InnoDB中的行锁
行锁(Row Lock)也称为记录锁,顾名思义,就是锁住某一行(某条记录Row)。需要注意的是,Mysql服务器并没有实现行锁机制,行级锁只在存储引擎层实现。
优点:锁定力度小,发生锁冲突概率低,可以实现的并发度高。
缺点:对于锁的开销比较大,加锁会比较慢,容易出现死锁。
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用行级锁
记录锁(Record Locks)
间隙锁(Gap Locks)
Mysql在Repeatable Read 隔离界别下是可以解决幻读问题的,解决方案有两种,可以采用MVCC方案解决,也可以采用加锁方案解决。但是在使用加锁方案解决时有个一大问题,就是事务在第一次执行读取操作的时候,那些幻影记录尚不存在,我们无法给这些幻影记录 加上记录锁。InnoDB提出了一种称之为Gap Locks的锁,官方的类型名称为:LOCK_GAP
id值为8的记录加了gap锁,意味着不允许别的事务在id值为8的记录前边的间隙插入新的记录。
gap锁的提出仅仅是为了防止插入幻影记录而提出的,虽然有共享gap锁和独占gap锁的说法,但是他们起到的作用是相同的。而且如果对一条记录加了gap锁(不论是共享gap锁还是独占gap锁),并不会限制其他事务对这条记录加记录锁或者继续加gap锁。
间隙锁扩大了锁住的范围,可能会引起死锁
临键锁(Next-Key Locks)
临键锁=记录锁+间隙锁
插入意向锁(Insert Intention Locks)
页锁
从对待锁的态度划分为:乐观锁、悲观锁
从对待锁的态度来看锁的话,可以将锁分为乐观锁和悲观锁,从名字可以看出这两种锁是两种看待数据并发的思维方式。需要注意的是,乐观锁和悲观锁并不是锁,而是锁的设计思想。
悲观锁(数据库的锁层面)
乐观锁(程序层面)
两种锁的适用场景
按照加锁的方式划分:显式锁、隐式锁
隐式锁
其他锁之-全局锁
其他锁之死锁
两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁
如何处理死锁
方式1:等待,直到超时(innodb_lock_wait_timeout=50s)
方式2:使用死锁检测进行死锁处理
锁的内存结构
type_mode的信息
锁监控
视频链接:B站