Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 📝 Notes
    • Algorithm
      • Algorithm - Bloom Filter
      • Algorithm - Disjoint Set
      • Algorithm - Fast Power
      • Algorithm - KMP
      • Algorithm - Monotonic Stack
      • Algorithm - RB-Tree
      • Algorithm - Regular Expression
      • Algorithm - Sliding Window
      • Online Judge - I/O
    • C++
      • C++ - Const
      • C++ File I/O
      • C++ - Object Layout
      • C++ - Operator Overload
      • C++ - Polymorphism
      • C++ STL algorithm
      • C++ STL map
      • C++ STL multimap
      • C++ STL priority_queue
      • C++ STL set
      • C++ STL string
      • C++ STL unordered_map
      • C++ STL vector
      • C++ - Smart Pointer
      • C++ - Template & Genericity
    • Compiler
      • ANTLR - Basic
      • Compiler - LLVM Architecture
      • Compiler - Multi-version GCC
    • Cryptography
      • Cryptography - Certbot
      • Cryptography - Digital Signature & PKCS #7
      • Cryptography - GPG
      • Cryptography - JWT
      • Cryptography - Keystore & Certificates
      • Cryptography - OAuth 2.0
      • Cryptography - Java 实现对称与非对称加密算法
      • Cryptography - TLS
    • DevOps
      • DevOps - Travis CI
    • Docker
      • Docker - Image & Storage Management
      • Docker - Image
      • Docker - Libcontainer
      • Docker - Multi-Arch Image
      • Docker - Multi-Stage Build
      • Docker - Network
      • Docker - Orchestration & Deployment
      • Docker - Overview
      • Docker - Service Building
      • Docker - Volume & Network Usage
      • Docker - Volume
      • Linux - Control Group
      • Linux - Namespace
    • Git
      • Git - Branch & Merge
      • Git - Cached
      • Git - Cherry Pick
      • Git - Commit
      • Git - Patch
      • Git - Proxy
      • Git - Rebase
      • Git - Reset
      • Git - Stash
      • Git - Theme for Git-Bash
    • Java
      • JVM - Synchronized
      • JVM - Volatile
      • Java - Annotation 注解
      • Java - BIO & NIO
      • Java - Class Path
      • Java - Condition and LockSupport
      • Java - Current Timestamp
      • Java - Deep Copy
      • Java - 运行环境配置
      • Java - Equals
      • Java - Exporting JAR
      • Java - Javadoc
      • Java - Lock
      • Java - Maven 项目构建工具
      • Java - References
      • Java - Reflection Mechanism
      • Java - String Split
      • Java - Thread Pool
      • Java - Thread
      • Tomcat - Class Loader
      • Tomcat - Container
    • Linux
      • addr2line
      • cut
      • df
      • du
      • fallocate
      • find
      • fio
      • grep
      • groupadd
      • gzip
      • head / tail
      • hexdump
      • iostat
      • iotop
      • kill
      • ldd
      • lsof
      • ltrace / strace
      • mpstat
      • netstat
      • nm
      • pidstat
      • pmap
      • readlink
      • readlink
      • rpm2cpio / rpm2archive
      • sort
      • tee
      • uniq
      • useradd
      • usermod
      • watch
      • wc
      • which
      • xargs
    • MS Office
      • MS Office - Add-in Dev
      • MS Office - Application
    • MySQL
      • InnoDB - Architecture
      • InnoDB - Backup
      • InnoDB - Checkpoint
      • InnoDB - Critical Features
      • InnoDB - Files
      • InnoDB - Index
      • InnoDB - Insert Buffer
      • InnoDB - Lock
      • InnoDB - Partition Table
      • InnoDB - Table Storage
      • MySQL - Server Configuration
      • MySQL - Storage Engine
    • Network
      • Network - ARP
      • Network - FTP
      • Network - GitHub Accelerating
      • HTTP - Message Format
      • HTTP - POST 提交表单的两种方式
      • Network - Proxy Server
      • Network - SCP
      • Network - SSH
      • Network - TCP Congestion Control
      • Network - TCP Connection Management
      • Network - TCP Flow Control
      • Network - TCP Retransmission
      • Network - Traceroute
      • Network - V2Ray
      • Network - WebSocket
      • Network - Windows 10 Mail APP
      • Network - frp
    • Operating System
      • Linux - Kernel Compilation
      • Linux - Multi-OS
      • Linux - Mutex & Condition
      • Linux - Operations
      • Linux: Package Manager
      • Linux - Process Manipulation
      • Linux - User ID
      • Linux - Execve
      • OS - Compile and Link
      • OS - Dynamic Linking
      • OS - ELF
      • Linux - Image
      • OS - Loading
      • OS - Shared Library Organization
      • OS - Static Linking
      • Syzkaller - Architecture
      • Syzkaller - Description Syntax
      • Syzkaller - Usage
      • Ubuntu - Desktop Recover (Python)
      • WSL: CentOS 8
    • Performance
      • Linux Performance - Perf Event
      • Linux Performance - Perf Record
      • Linux Performance - Perf Report
      • Linux Performance - Flame Graphs
      • Linux Performance - Off CPU Analyze
    • PostgreSQL
      • PostgreSQL - ANALYZE
      • PostgreSQL - Atomics
      • PostgreSQL - CREATE INDEX CONCURRENTLY
      • PostgreSQL - COPY FROM
      • PostgreSQL - COPY TO
      • PostgreSQL - Executor: Append
      • PostgreSQL - Executor: Group
      • PostgreSQL - Executor: Limit
      • PostgreSQL - Executor: Material
      • PostgreSQL - Executor: Nest Loop Join
      • PostgreSQL - Executor: Result
      • PostgreSQL - Executor: Sequential Scan
      • PostgreSQL - Executor: Sort
      • PostgreSQL - Executor: Unique
      • PostgreSQL - FDW Asynchronous Execution
      • PostgreSQL - GUC
      • PostgreSQL - Locking
      • PostgreSQL - LWLock
      • PostgreSQL - Multi Insert
      • PostgreSQL - Plan Hint GUC
      • PostgreSQL - Process Activity
      • PostgreSQL - Query Execution
      • PostgreSQL - Spinlock
      • PostgreSQL - Storage Management
      • PostgreSQL - VFD
      • PostgreSQL - WAL Insert
      • PostgreSQL - WAL Prefetch
    • Productivity
      • LaTeX
      • Venn Diagram
      • VuePress
    • Solidity
      • Solidity - ABI Specification
      • Solidity - Contracts
      • Solidity - Expressions and Control Structures
      • Solidity - Layout and Structure
      • Solidity - Remix IDE
      • Solidity - Slither
      • Solidity - Types
      • Solidity - Units and Globally Available Variables
    • Vue.js
      • Vue.js - Environment Variable
    • Web
      • Web - CORS
      • Web - OpenAPI Specification
    • Wireless
      • Wireless - WEP Cracking by Aircrack-ng
      • Wireless - WPS Cracking by Reaver
      • Wireless - wifiphisher

InnoDB - Lock

Created by : Mr Dk.

2020 / 10 / 17 20:20

Nanjing, Jiangsu, China


锁机制用于管理对共享资源的访问,使用户能够最大程度利用数据库的并发访问,同时又能以一致的方式读取和修改数据。

Lock in InnoDB

InnoDB 存储引擎会在行级别上对表数据进行加锁。InnoDB 存储引擎实现了两种标准行级锁:

  • S Lock (共享锁,读锁) - 允许事务读一行数据
  • X Lock (排他锁,写锁) - 允许事务删除或更新一行数据

行为与常见的读写锁一致:多个事务可以同时获取一行的读锁,但是只有获取一行写锁的事务可以修改该行数据。当事务 1 上的锁与事务 2 上的锁都不改变行数据时,称为 锁兼容;否则称为 锁不兼容。

S LockX Lock
S Lock兼容不兼容
X Lock不兼容不兼容

InnoDB 还支持多粒度的锁定 - 允许事务在行级别上的锁和表级别上的锁同时存在。意向锁 (Intention Lock) 用于将锁定的对象分为多个层次,表示事务希望在更细的粒度上进行加锁:

  • IS Lock (意向共享锁)
  • IX Lock (意向排他锁)

如果事务要对某个页上的记录 r 上 X 锁,那么首先需要对数据库、表、页上 IX 锁,最后对记录上 X 锁。若其中任意一次上锁操作导致了等待 (不兼容),都需要等待粗粒度锁释放后再进一步上锁。规律总结如下:

  • 意向锁之间兼容
  • S Lock 之和 S/IS Lock 兼容
  • X Lock 和其它所有锁都不兼容
IS LockIX LockS LockX Lock
IS Lock兼容兼容兼容不兼容
IX Lock兼容兼容不兼容不兼容
S Lock兼容不兼容兼容不兼容
X Lock不兼容不兼容不兼容不兼容

InnoDB 中,意向锁实际上就是表级别的锁,不会阻塞除全表扫描以外的任何请求。

Consistent Non-locking Read

一致性非锁定读 指 InnoDB 存储引擎通过管理多个版本的控制来读取数据库中的数据。假设当前读取的行正在进行 UPDATE 或 DELETE 操作,则不会因此去等待行上的 (X) 锁释放,而是直接读取行的 快照数据,从而避免了阻塞。快照数据是通过 undo 段实现的,undo 段本用于在事务中回滚数据,因此没有额外开销;另外,读取快照数据也不需要上锁。

每个行记录的快照可能会有多个版本,这就是所谓的行多版本并发控制 (Multi Version Concurrency Control, MVCC)。在不同的 事务隔离级别 下,使用的是不同版本的行快照。

  • READ COMMITTED 事务隔离级别下,读取行的最新快照数据 (其它事务对行的更改会被当前事务读取到,违反了 ACID 中的隔离性)
  • REPEATABLE READ 事务隔离级别下,读取事务开始时的快照版本

Consistent Locking Read

在某些情况下,用户需要 显式 对数据库读取操作进行加锁来保证数据一致性。InnoDB 存储引擎对 SELECT 语句支持两种 一致性锁定读 操作:

  • SELECT ... FOR UPDATE - 对读取的行记录加 X 锁
  • SELECT ... LOCK IN SHARE MODE - 对读取的行记录加 S 锁

上述两种语句必须出现在事务中。事务提交后,锁也就被释放了。

Auto Increment

InnoDB 存储引擎对每一个 含有自增长值 的表都带有一个自增长计数器,插入操作会根据计数器的值 + 1 赋予自增长列。该值可能会遭到并发修改,因此存在 AUTO-INC Locking,这是 MySQL 5.1.22 版本之前的实现方式。为了提高插入性能,锁不是在事务完成后才释放,而是完成执行插入自增长列的 SQL 语句后立刻释放该锁。

MySQL 后续支持了较为轻量级的自增长实现方式,即使用互斥量。但是可能带来的问题是每次插入时自增长的值可能不是连续的。


Lock Algorithm

行锁包含了三种算法:

  • Record Lock - 单个行记录上锁
  • Gap Lock - 锁定一个范围,但不锁定记录本身
  • Next-Key Lock - 锁定一个范围,并锁定记录本身

当查询的索引中包含 唯一索引 时,InnoDB 存储引擎会将 Next-key Lock 降级为 Record Lock (因为没必要锁定一个范围),从而提高系统并发性。这些锁用于解决各种锁问题。

Phantom Problem

幻读 问题。在同一事务下,连续执行两次同样的 SQL 语句,得到的记录数不一样 (特指数据新增或删除)。比如在一个事务内执行了两次如下语句:

SELECT * FROM t WHERE a > 2 FOR UPDATE;

在该事务执行两次该语句之间,另一个事务插入了一个值为 4 的值,因此第二次执行该语句会得到不一样的结果。幻读违反了事务的隔离性。InnoDB 的 REPEATABLE READ 事务隔离等级下使用 Next-Key Locking 来解决幻读问题,即对 (2, +∞) 的范围加 X 锁,对该范围的任何插入都是不允许的。

Dirty Read

脏数据指事务对缓冲区中行记录修改但没有被提交的数据。如果一个事务读到了另一个事务中未提交的数据,就是脏读。脏读违反了数据库的隔离性,只有在 READ UNCOMMITTED 事务隔离等级下才可能会发生。

在修改事务时加 X 锁,当事务提交后再解锁,可以解决脏读问题。

Unrepeatable Read

不可重复读 指在一个事务内多次读取同一数据集合,同时另一事务也访问了同一数据集合并进行了 DML 操作 (并提交) - 第一个事务两次读取到的数据可能不一致 (特指数据更新)。由于不可重复读读到的是已经提交的数据,因此违反的是 ACID 中的一致性要求。

在 InnoDB 存储引擎中,还是通过 Next-Key Lock 算法来避免不可重复读的问题。在该算法下,对索引的扫描,不仅会锁住扫描到的索引,还会锁住索引的覆盖范围。实现该算法的事务隔离等级为 READ REPEATABLE。

Lost Update

丢失更改 发生于一个事务的更新被另一个事务的更新覆盖。为了避免这个问题,需要让事务操作 串行化 - 在用户读取记录时上 X 锁,等事务提交后再释放 X 锁。

Dead Lock

死锁指的是两个或两个以上的事务在执行过程中,因争夺锁资源而造成的互相等待的现象。若无外力作用,则事务无法推进下去。解决死锁的方式是 超时 - 当一个事务等待时间超过阈值时,就让其中的一个事务回滚,另一个等待中的事务自然继续进行。但是根据 FIFO 的顺序选择事务进行回滚比较暴力,理论上应该选择 undo 代价较小的事务进行回滚。

当前数据库普遍使用 wait-for graph 进行死锁检测 - 构造对资源使用的图,如果图中存在回路,那么存在死锁。

Lock Escalation

锁升级 指的是当细粒度的锁数量过多,而锁本身是一种稀缺资源,那么可以将大量细粒度的锁升级为少量粗粒度的锁,从而保护了系统资源,防止系统使用过多内存来维护锁。对于 SQL Server 来说,由于锁是稀缺资源,锁升级会带来效率上的提高,但也可能导致并发性能的降低。而对于 InnoDB 存储引擎来说,由于不是根据每个记录产生锁,而是根据每个页对锁进行管理,因此不管事务锁住页中的几条记录,开销都是一致的。


References

知乎专栏 - 把 MySQL 中的各种锁及其原理都画出来

CSDN - 数据库 不可重复读与幻读的区别


Edit this page on GitHub
Prev
InnoDB - Insert Buffer
Next
InnoDB - Partition Table