MySQL锁定机制分析--行级锁定

上一节我们概述了MySQL的锁机制,讲到了MySQL锁定机制分析–表级锁定,今天我们来看一下行级锁定。 行级锁定不是MySQL本身自己实现的锁机制,而是其他引擎实现的,其中有InnoDB,NDB Cluster(MySQL分布式存储引擎)。由于锁定粒度最小,实现也相对复杂,每一种引擎实现的方式也不大相同,这里以使用最为广泛的InnoDB为例来介绍。

InnoDB行锁简介

InnoDB的行级锁定分为2种类型:

  • 共享锁 shared (S)
  • 排它锁 exclusive (X)

而为了使得表锁和行锁共存,InnoDB引入了意向锁的概念,也就有了意向共享锁和意向排它锁这2种。 当一个事务需要给某些资源加锁的时候,如果

  • 一个共享锁已经(正在)锁定当前资源,那么再加一个共享锁,但不能加排他锁
  • 一个排它锁已经(正在)锁定当前资源,则事务只能等待其释放后才能再加锁
    意向锁的作用就是当希望锁定资源而遇到已经在资源上面的排它锁时可以添加的一种锁类型。如果需要

  • 共享锁,那么在表上添加一个意向共享锁(此锁可以多个并存)

  • 排它锁,那么在表的某行(或某些行)添加一个排它锁(前提是之前没有其他事务添加意向排它锁,否则依然需要加入等待队列,也就是说此锁不可以多个并存,有且只能有一个加在当前表)

那么,MySQL实际上就存在4种锁类型,下面是这些锁的共存逻辑关系(lock type compatibility matrix)。√代表可以共存(Compatible),×表示加锁冲突(Conflict)

排它锁(X) 意向共享锁(IS) 意向排它锁(IX) 共享锁(S)
共享锁(S) × ×
排它锁(X) × × × ×
意向共享锁(IS) ×
意向排它锁(IX) × ×

行级锁定演示与死锁(Deadlock)

当使用行级锁定的时候,往往会发生死锁,死锁的概念比较简单,就是互相等待对方释放资源而导致的停滞。 这里我们简单展示一下MySQL InnoDB在使用行级锁定的情况下发生的死锁。 使用行级锁定的方法是:
SELECT ... LOCK IN SHARE MODE sets an IS lock and SELECT ... FOR UPDATE sets an _IX_lock.

  1. 建立测试表,插入测试数据,并加上共享锁。

create_test_table

  1. 使用另一个session提交一个获取写锁的事务,由于读写锁的冲突,阻塞。

session2_trans

  1. 当前session提交相同事务,由于当前session需要一个写锁来操作当前行,但另一session已经在等待获取此写锁,因而发生死锁,InnoDB根据事务量来选择回滚相应的session事务,同时回滚的事务返回一个死锁的error。

deadlock