MySQL 锁

基于锁的并发控制,给竞争资源加锁,阻塞读、写操作来解决事务之间的竞争条件,最终保证事务的可串行化。

基础概念

table-level locking 表级锁,所有存储引擎都支持。指标 table_locks_waited 观察表锁。
row-level locking 行级锁,InnoDB支持,行锁加在索引上,因此优化器不走索引,会导致锁全表。指标 row_lock_current_waits 观察行锁。
S mode share,共享锁
X mode exclude,互斥锁
IS mode 意向共享锁
IX mode 意向互斥锁,表级锁,执行 DDL 前快速判断是否允许锁表
Optimistic Lock 乐观锁,假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。适用于并发度低的场景。MySQL 无乐观锁实现,可以通过版本号来实现。
Pessimistic Lock 悲观锁,假设会发生并发冲突,屏蔽一切可能违反数据完整性的操作。MySQL 的锁都是悲观锁。

Two-Phase Locking

两阶段锁,2PL 和 2PC 是两回事。
InnoDB 实现中,行锁也不是在事务开启时就占用,而是执行到特定语句时才加上,等待事务结束时释放。因此建议在事务中,把最可能造成冲突的锁尽量往后放。
另外,start transaction 不是立刻开启事务,而是执行第一个sql时,事务才真正开启。

deadlock

死锁,并发系统中不同线程出现循环依赖,涉及的线程都在等待别的线程释放资源,导致这几个线程都进入无限等待的状态。
解除死锁有2种策略:

  1. 默认 innodb_lock_wait_timeout=50,事务等待50秒,超时回滚;
  2. 默认 innodb_deadlock_detect=on,开启死锁检测,主动回滚其中一个死锁事务,其它事务得以继续执行。
    两个策略都是默认开启,但策略二有性能问题,死锁检测O(n),极端情况下CPU利用率上升,但 TPS 反而下降。

命令 SHOW INNODB STATUS 查询引发死锁的SQL,事务已经获得的锁,正在等待什么锁,以及被回滚的事务等

next-key lock

RR 隔离级别下,使用范围条件查询,间隙锁 可以防止幻读。

SELECT * FROM test WHERE id < 3 FOR UPDATE;

这是当前读,间隙锁将锁住(2,5)这个间隙,增大死锁的概率,因此建议:

  1. 尽量使用相等条件查询;
  2. 使用 RC 隔离级别。

参考文献

MySQL 锁

上一篇:MySQL MVCC


下一篇:MySQL 输入查询