锁类型
根据 SQL 行为,分为 2 种类型锁:
- S 锁,共享锁
- X 锁,排他锁
锁算法又有 2 种:
- 行锁
- 间隙锁
根据锁的粗粒度,还有意向锁(InnoDB事务并发决策用的,可以不用关注)
事务隔离级别和锁
根据不同方式的使用锁, MySQL 实现了 4 种事务隔离级别:
事务隔离级别 | 读 | 写 |
---|---|---|
READ UNCOMMITTED(读取未提交) | 无 S 锁,最新版本 | 有 X 锁 & 行锁 |
READ COMMITTED(读取已提交) | 无 S 锁,最新版本或最新历史副本 | 有 X 锁 & 行锁 |
REPEATABLE READ(可重复读) | 无 S 锁,指定历史副本 | 有 X 锁 & 行锁或间隙锁(特定语法) |
SERIALIZABLE(可串行化) | 有 X 锁(意向锁会参与让事务串行) | 有 X 锁 & 间隙锁(意向锁会参与让事务串行) |
因为锁的使用方式不同,进而可能出现以下问题:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 | 丢失更新 |
---|---|---|---|---|
READ UNCOMMITTED(读取未提交) | Y | Y | Y | Y |
READ COMMITTED(读取已提交) | N | Y | Y | Y |
REPEATABLE READ(可重复读) | N | N | 分情况,特定语法后缀可以无幻读 | Y |
SERIALIZABLE(可串行化) | N | N | N | N |
一致性非锁定读
READ COMMITTED(读取已提交)和REPEATABLE READ(可重复读)的读,会根据 MVCC 机制,读历史版本数据(不同的是版本的定义不同)
一致性非锁定读,性能是高效的,主要有以下 2 个方面:
- 并发,因为读的是历史版本数据,因此无视是否有排他锁
- 历史版本无额外消耗。历史版本来至事务开始前的 UNDO 记录,不是因为该功能需要额外的拷贝操作
一致性锁定读
SELECT 语句后缀:
- SELECT ... FOR UPDATE ,显示声明加 X 锁
- SELECT ... LOCK IN SHARE MODE ,显示声明加 S 锁
根据事务隔离级别不同,可能为行锁,或升级为间隙锁
间隙锁
间隙锁,指定索引前后区间的记录均加锁
非唯一索引的 SQL 语句,根据事务隔离级别不同,可以升级为间隙锁
注意这里用词为唯一索引的记录,而没有用聚集索引
因为聚集索引可能为组合索引,这样,部分聚集索引参与的 SQL 的记录就不是唯一的了