InnoDB存储引擎中的锁

原创
2019/08/02 15:51
阅读数 435

两种锁概念:

  1. lock
    • lock的对象是事务
    • 锁定数据中的对象:
    • 一般lock的对象仅在事务commit或rollback后进行释放
      • 不同的隔离级别,情况不同
    • 有死锁机制
    • SELECT * FROM information_schema.INNODB_TRX;
    • SELECT * FROM information_schema.INNODB_LOCKS;
    • SELECT * FROM information_schema.INNODB_LOCK_WAITS;
  2. latch
    • 闩锁(轻量级的锁)
    • 持续时间长,则性能非常差
    • 分为:
      • mutex(互斥)
      • rwlock(读写锁)
    • 没有死锁检测机制
    • SHOW ENGINE INNODB MUTEX;
    • SHOW ENGINE INNODB STATUS;

对比

类别 lock latch
对象 事务 线程
保护 数据库内容 内存数据结构
持续时间 整个事务过程 临界资源
模式 行锁、表锁、意向锁 读写锁、互斥量
死锁 通过waits-for graph、time out等机制进行死锁检测处理 无死锁检测与处理机制。仅通过应用程序加锁的顺序(lock leveling)保证无死锁的情况发生
存在于 Lock Manager 的哈希表中 每个数据结构的对象中

锁类型

锁的类型:

  • 共享锁(S Lock)
    • 允许事务读一行数据
    • 锁兼容(Lock Compatible)
  • 排他锁(X Lock)
    • 允许事务删除或更新一行数据
    • 锁不兼容
类型 X S
X 不兼容 不兼容
S 不兼容 兼容

多粒度(granular)锁定

  • 允许事务在行级上的锁和表级上的锁同时存在
  • InnoDB存储引擎支持:意向锁(Intention Lock)
    • 如需对最下层的记录加X锁,则需要对上层的数据库记录加IX锁
    • MySQL中意向锁即为:表级别的锁
    • 设计目的:
      • 为了在一个事务中揭示下一行将被请求的锁类型
    • 支持两种意向锁:
      • 意向共享锁(IS Lock)
        • 事务想要获得一张表中某几行的共享锁
      • 意向排他锁(IX Lock)
        • 事务想要获得一张表中某几行的排他锁
    • 意向锁不会阻塞除全表扫以外的任何请求
graph TB
DB[数据库A]
T[表]
P[页]
R[记录]
DB-->T
T-->P
P-->R
锁类型 IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容

一致性读

  • 一致性非锁定读
    • MVCC
      • 多版本控制
      • 如果读取的行,正在执行DELETE/UPDATE操作,则读操作不会等待行上锁的释放,直接读取快照
        • 直接读取undo段
          • 用于事务回滚
        • 不需要额外的快照开销
      • 提高并发
  • 一致性锁定读
    • 显式的对数据库读取操作加锁
    • 两种锁定读(locking read)操作:
      • SELECT ... FOR UPDATE
        • 对读取行加X锁
        • 其他事务不能对已锁定的行加上任何锁
        • 其他事务还是可以继续读取
      • SELECT ... LOCK IN SHARE MODE
        • 对读取行加S锁
        • 其他事务可以再次加S锁
        • 如果其他事务加X锁,则阻塞

自增字段锁问题

InnoDB内存结构钟,对每个自增长值的表,都有一个自增长计数器(auto-increment counter)。

  • 当插入时,计数器初始化
    • SELECT MAX(auto_inc_col) FROM t FOR UPDATE
  • AUTO-INC Locking
    • 一种特殊的表锁机制
    • 不在事务中控制
    • 自增值插入后,立即释放
    • INSERT ... SELECT
      • 大数据量的插入会影响插入的性能
  • 轻量级互斥量
    • innodb_autoinc_lock_mode
      • 0
        • 5.1.22之前
        • 通过表锁的AUTO-INC Locking方式
      • 1
        • 默认值
        • simple inserts
          • 会用互斥量(mutex)去对内存中的计数器进行累加的操作
        • bluk inserts
          • 使用传统表锁的AUTO-INC Locking方式
        • 如果不考虑回滚操作,自增长的值还是连续增长的
      • 2
        • insert-like
          • 自增长都是通过互斥量
        • 性能最高
        • 问题
          • 每次插入时,自增长值不连续
          • 基于Statement-Base Replication会出现问题
            • 应该配合row-base replication一起使用
  • InnoDB存储引擎中,自增长值的列必须是索引,同时必须是索引的第一个列

自增长类型:

  • insert-like
    • 指所有的插入语句
  • simple inserts
    • 指可以在插入前就确定插入行数的语句
  • bulk inserts
    • 指在插入前不可确定行数的语句
  • mixed-mode inserts
    • 插入中有一部分的值是自增长的,有一部分是确定的

InnoDB会自动对外键加一个索引

  • 避免表锁

算法

锁的算法:

  • Record Lock
    • 单行记录上的锁
    • 锁索引
  • Gap Lock
    • 间隙锁
    • 锁定一个范围
      • 不包含记录本身
  • Next-Key Lock
    • Gap Lock + Record Lock
    • 锁定一个范围
      • 并且锁定记录本身
    • 查询时,也是用此算法
    • 当查询时,发现索引唯一,则降级为 Record Lock

Phantom Problem问题

  • 是指,在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。
  • InnoDB使用Next-Key Lock算法,避免此问题
    • 间隙锁(X锁)

锁问题

1. 脏读

脏读(Dirty Read)

  • 脏数据
    • 指,事务对缓冲池中的行记录进行了修改,但是还没有提交(commit)
  • 在不同的事务下,当前事务可以读到另外事务未提交的数据(脏数据)

发生于:READ UNCOMMITTED

  • 常用于:replication环境中的slave节点

2. 不可重复读

指,在一个事务内多次读取同一数据集合

  • 两次读到的数据不一致
    • 读到了其他事务已经提交的数据
  • 违反了数据库事务一致性
  • READ COMMITTED 可解决
    • Next-Key Lock 的Gap锁,避免其他事务对范围内数据修改
      • InnoDB 的 READ REPEATABLE 采用Next-Key Lock也可以避免

3. 丢失更新

更粗粒度锁,避免此问题

后续修改,覆盖前一次更新

FOR UPDATE

阻塞

InnoDB中,

  • innodb_lock_wait_timeout用来控制等待的时间
    • 默认50秒
  • innodb_rollback_on_timeout用来设定是否在等待超时时回滚事务
    • 默认OFF,不回滚
    • 需要注意
    • 特别是在间隙锁的超时情况

死锁

死锁

  • 指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。

解决方案:

  • 超时
    • 如果操作更新了很多行,占用了较多的undo log
    • 普遍采用wait-for graph
      • 等待图
        • 节点:事务
        • 边:
          • 事务T1等待事务T2所占用的资源
          • 事务T1最终等待T2所占用的资源
            • 事务之间在等待相同的资源
            • 事务T1发生在事务T2的后面
      • 进行:死锁检测(主动)
        • 判断是否存在回路
        • 如果存在,则死锁,则回滚undo量最小的事务
      • 存储:
        • 锁的信息链表
        • 事务等待链表

死锁因素:

  • 系统中事务的数量,数量越多发生死锁的概率越大
  • 每个事务操作的数量越多,发生死锁的概率越大
  • 操作数据的集合,越小则发生死锁的概率越大

锁升级

锁升级(Lock Escalation)

InnoDB,根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式

  • 不论事务锁住一个记录还是多个记录,其开销是一致的
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
2 收藏
0
分享
返回顶部
顶部