MySQL锁

全局锁

flush tables with read lock,执行此条命令,整个数据库处于只读状态
unlock tables, 释放全局锁,会话断开时,也会自动释放全局锁

一般用来全库逻辑备份

表级锁:MySQL 里面表级别的锁有这几种:

    • 表锁:通过lock tables 语句可以对表加表锁,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。
    • 元数据锁:当我们对数据库表进行操作时,会自动给这个表加上 MDL,对一张表进行 CRUD 操作时,加的是 MDL 读锁;对一张表做结构变更操作的时候,加的是 MDL 写锁;MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。
    • 意向锁:当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。意向锁的目的是为了快速判断表里是否有记录被加锁

行级锁:InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。

记录锁(Record Lock)

  • 锁住某行记录,分为读写锁,事务提交后自动释放,例如select * from table_name where id = 1 for update;就给id=1这行记录上了写锁

间隙锁(Gap Lock)

  • 锁住行与行之间的间隙,防止其它事务在间隙中插入数据,产生幻读,间隙锁是不互斥的(如果涉及到记录锁或者临键锁,还是会互斥阻塞),两个事务可以拥有同一段间隙的间隙锁,但要插入数据时发现这段间隙被其它事务锁上了就插不了了。间隙锁是为了解决幻读,防止其它事务在区间内插入数据

临键锁(Next-Key Lock)

  • 间隙锁 + 记录锁,加临键锁的时候是先加间隙锁,后加记录锁,这就有可能出现加间隙锁能成功,加记录锁被阻塞,然后间隙锁与其它事务发生死锁
  • 前开后闭区间,锁住某行以及这一行之前的间隙,如(1, 3],锁住3这一行和1到3行之间的间隙,因为有记录锁,会产生读写互斥,间隙锁之间不互斥

插入意向锁:

  • 插入意向锁是一个间隙锁,但这个间隙锁实际上锁住的不是一个区间,而是区间中插入的那个点,所以算是一种特殊的间隙锁,插入意向锁和插入意向锁会互斥,即两个事务可以在同一个区间插入,但不能在同一个区间上相同的点插入;插入意向锁与间隙锁互斥,即插入的点所处的区间不能被其它事务的间隙锁锁住

加锁算法

抛开隔离级别谈加锁,都是耍流氓。
InnoDB 的加锁行为必须结合事务隔离级别来理解。

一、读未提交(Read Uncommitted)

  • 增(INSERT)
    插入成功后,对新插入的记录加 记录锁,防止其他事务修改该记录。
  • 删(DELETE)
    需要获取待删除记录的 记录锁
    保证删除过程中其他事务无法使用该记录,且删除后不能再对其进行操作。
  • 改(UPDATE)
    对需要修改的记录加 记录锁
  • 查(SELECT)
    • 普通 SELECT:不上锁,直接读取最新数据(包括未提交的数据)。
    • SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE
      仅加 记录锁不加间隙锁

二、读已提交(Read Committed)

  • 增(INSERT)
    插入后对新记录加 记录锁
  • 删(DELETE)
    对目标记录加 记录锁,保证删除过程的安全性。
  • 改(UPDATE)
    对被修改的记录加 记录锁
  • 查(SELECT)
    • 普通 SELECT:不上锁,通过 MVCC 读取已提交的数据。
    • SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE
      仅加 记录锁不锁间隙

三、可重复读(Repeatable Read,InnoDB 默认)

  • 增(INSERT)
    • 插入时使用 插入意向锁
    • 插入完成后,记录会被加上 记录锁(隐式锁,非立即可见)
  • 删(DELETE)
    对删除范围加 临键锁(Next-Key Lock)
    防止其他事务在该区间内插入新记录。
  • 改(UPDATE)
    对目标记录加 临键锁
  • 查(SELECT)
    • 普通 SELECT:不上锁,通过 MVCC 读取快照数据。
    • SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE
      临键锁同时锁记录和间隙

四、串行化(Serializable)

  • 增(INSERT)
    使用 插入意向锁,插入完成后记录被加上 记录锁
  • 删(DELETE)
    对删除区间加 临键锁,防止其他事务插入。
  • 改(UPDATE)
    对修改范围加 临键锁
  • 查(SELECT)
    • 普通查询会 自动转化为
      SELECT ... LOCK IN SHARE MODE
      对读取范围加 临键锁,锁定间隙。