MySQL锁的类型

数据库锁的类型主要有:

  • 表锁
  • 行锁
  • 间隙锁
  • 临键锁

知识点助记

把数据库比作图书馆,看书就是读数据,借还书就是写数据

  • 表锁:就像图书馆闭馆清点。谁也不准进来,谁也不让出去。优点是管理简单,缺点是效率低。
  • 行锁:就像读者用个人借书卡锁定了某本具体的书。其他人可以随便看,借还别的书,但是被锁定的这本书,在被归还(事务结束)前
    别人不能借走(修改)。
  • 间隙锁:图书馆的书架不是连续的,有些书架上是空着的。间隙锁就是锁住这些空位置,禁止任何人往这个空位里插入新书。但是他不锁任何现有的书
  • 临键锁:这其实就是行锁+间隙锁的组合技。他不但要锁住你想要的那本书,还要锁住他旁边的空位。这是在InnoDB在默认隔离级别(可重复读)下防止幻读的手段。

具体实现

  1. 表锁:就是锁住整张表,实现简单,开销小。
LOCK TABLES table_name READ; -- 加读锁(共享锁),别人可读不可写
LOCK TABLES table_name WRITE; -- 加写锁(排他锁),别人既不可读也不可写
-- ... 你的操作 ...
UNLOCK TABLES; -- 释放锁
  1. 行锁:锁住表中单行或多行记录,并发度高。

行锁是隐式的,在事务中自动加锁

BEGIN;
UPDATE user SET balance = balance - 100 WHERE id = 1; -- 这条语句会自动给id=1的行加上排他锁(X锁)
-- ... 其他操作 ...
COMMIT; -- 事务提交时,锁自动释放
  • 在UPDATE,DELETE,SELECT….FOR UPDATE等语句执行时,都会自动加上行锁
  1. 间隙锁 && 临键锁 :锁住一个索引区间(开区间,不包含记录本身)
    主要是为了防止幻读。同样也是隐式的,在可重复读隔离级别下自动启动

当你执行 SELECT * FROM user WHERE age BETWEEN 10 ADN 20 FOR UPDATE; 时,InnoDB不仅会锁住age在10-20之间所有已存在的记录(行锁)
还会锁住age在10-20之间的空闲空间(间隙锁),阻止任何新纪录插入到这个区间(如age=15的新用户)

注意事项

行锁不是直接锁磁盘上的记录!
行锁是锁在索引上的,如果WHERE条件字段没有索引,InnoDB就无法精确定位到哪一行,只能锁整个表(升级为表锁)。