MySQL锁机制
本篇开始前先眼熟一些概念
排他锁(X锁):排他锁也称写锁,一个排他锁会阻塞其他排他锁和共享锁
共享锁(S锁):共享锁也称读锁,共享锁不会阻塞其他共享锁,但是会阻塞排他锁
意向排他锁(IX锁):事务想要获得某一表中的某几行的排他锁。
意向共享锁(IS锁):事务想要获得某一表中的某几行的共享锁。
排他锁和共享锁好理解,在这里简单介绍下意向锁:意向锁是表级别的锁,当某个事务想要对表或者表内
某一行加锁的时候,数据库就会自动对该表加上一个对应的意向锁。比如事务A想要对表A中某一行加上排他
锁,那么在加锁前数据库会自动先对表A加上一个意向排他锁。
那么为什么要加意向锁呢?我们都知道,当表中某一行被加了共享锁后,那么就不能对该行加上排他锁。假设
事务A对表A中某一行加了共享锁,事务B想要对表A整张表加排他锁,那么数据库就得扫描所有表A所有行,看
看是否有某一行被加了共享锁或排他锁,如果有那么事务B就被阻塞。可以看出,如果表很巨大,那么一行行扫
苗就会很耗时间,效率低。如果事务A在对该行上共享锁之前数据库自动对表A上了意向共享锁,那么事务B就想
要对表A上写锁时数据库只要判断表A的意向锁,发现有意向共享锁,那么事务B直接进入阻塞,而不用一行行扫
描。
MyISAM与InnoDB锁机制
MySQL有两种存储引擎,一种是MyISAM一种是InnoDB,这两者存储引擎支持的锁机制也不同,MyISAM
默认支持表锁,而InnoDB默认支持行锁。
MyISAM锁机制
由于MyISAM只支持表锁,因此对数据的查找和更新都会对整张表上锁,并发度低。锁的粒度大,没有InnoDB灵活。
InnoDB锁机制
InnoDB默认支持行锁,因此可以多个事务同时操作一张表中的不同数据,而不会导致数据不一致性,锁的粒度小,并发度高
一致性非锁定读
一致性非锁定读是InnoDB存储引擎在可重复读事务级别的默认读取方式,一致性非锁定读是指InnoDB通过多版本并发控制(MVCC)的
方式来读取当前执行数据库中行的数据。如果正读取的行记录正在执行更新或者删除操作,那么读取操作也不会等待
释放锁后再去读取,而是读取当前行的一个快照数据。快照数据是当前行之前版本的数据。
对于提交读和可重复读都支持一致性非锁定读机制,但是提交读和可重复读对快照版本的选择却是不同的,提交读对于
快照数据,总是读取被锁定行的最新一份快照数据。而重复度对于快照数据总是读取当前事务开始的时候最初的那个快照
数据版本。因此提交读可能会产生破坏了隔离性问题。
一致性锁定读
有些情况下我们要显式的对数据库读取操作进行加锁以保证数据的一致性。即通过显式的加锁语句对数据进行加锁。这种就称为一致性锁定读。
InnoDB行锁的三种算法
Record Lock(记录锁):单个行记录上的锁
Gap Lock(间隙锁):锁定一个范围,但是不包含记录本身
Next-Key-Lock:记录所+间隙锁,锁定一个范围,包含锁定记录本身。
InnoDB对于行的查询都是采用Next-Key-Lock方式,采用Next-Key-Lock方式主要是为了解决幻读。但是当查询的索引包含有唯一属性时,就会将
锁降级为记录锁,即锁住索引本身,而不是整个范围。
如何使用Next-Key-Lock避免幻读呢,如果一个范围查询语句,那么Next-Key-Lock会将该范围内的所有行都锁定,即使该行数据不存在,即对于
select * from t where a > 2 for update语句,它会对(2,+∞)区间进行锁定,即使某些数据行不存在,那么其他事务就不能在该区间内插入数据。
也就不会产生换幻读。
间隙锁还有一种应用场景就是范围更新的时候。范围更新和范围查找类时,会对整个范围加锁,如果其他事务想要对该范围做修改,就会被阻塞/