本篇主要根据 innodb 存储引擎的锁进行阐述, 包括分类, 算法, 以及锁的一些问题
一, 锁的概述
为了保证最大程度的利用数据库的并发访问, 又要确保每个用户能以一致的方式读取和修改数据, 为此锁就派上了用场, 也就是锁的机制. 锁机制也是用于区别数据库系统和文件系统的一个关节特性.
锁是为了支持对共享资源进行访问, 提供数据的一致性和完整性.
innodb 存储引擎支持行级别的锁, 不过也可以在其他很多的地方上锁, 比如, LRU 列, 删除, 添加, 移动 LRU 列中的元素.
innodb 存储引擎提供了一致性的非锁定读, 行级锁支撑, 行级锁没有额外的开销, 并可以同时保证并发和一致性.
二, innodb 锁
2.1,lock 和 latch
虽然两个都是 "锁", 但是两者有着截然不同的意义.
latch 为轻量级锁: 要求锁定的时间非常短, 在 innodb 中, 其又可以分为 mutex(互斥量)和 rwlock(读写锁), 其目的是用来保证并发线程操作临界资源的正确性, 没有死锁检查机制.
查看: show ENGINE innodb MUTEX
其中 os_waits 表示操作系统等待的次数, 当不能获得 latch 时, 操作系统就会进入等待状态, 等待被唤醒.
lock 为事务级锁: 用来锁定数据库中的对象, 比如, 表, 页, 行. 并且一般 lock 的对象仅在事务 commit 或者 rollback 后进行释放, 有死锁机制.
2.2,innodb 存储引擎中的锁
2.2.1, 锁的类型
共享锁(S Lock): 允许事务读一行数据, 具有锁兼容性质, 允许多个事务同时获得该锁.
排它锁(X Lock): 允许事务删除或更新一行数据, 具有排它性, 某个事务要想获得锁, 必须要等待其他事务释放该对象的锁.
X 锁和其他锁都不兼容, S 锁之和 S 锁兼容, S 锁和 X 锁都是行级别锁, 兼容是指对同一条记录 (row) 锁的兼容性情况.
此外, innodb 支持多粒度锁定, 这种锁允许事务在行级别和表级别上的锁同时存在, 称之为意向锁(Intention Lock), 意向锁将锁定的对象分为多个层次, 意味着事务在更细粒度上进行加锁. 意向锁设计的目的主要是为了在一个事务中揭示下一行将被请求的锁类型.
意向共享锁(IS Lock): 事务想要获得一张表中的某几行的共享锁
意向排它锁(IX Lock): 事务想要获得一张表中的某几行的排它锁
对数据库中的对象加锁, 类似于这棵树, 如下图所示:
若将上锁看成如上的这颗树, 那么对最下层对象的上锁, 也就是最细粒度的上锁, 首先需要对粗粒度进行上锁, 如上图所示, 如果我们需要对最底层的记录进行上 X 锁, 那么需要对数据库, 表, 页上意向锁 IX Lock, 最后对最底层的记录上 X 锁, 若其中的任意一个部分导致等待, 则该操作需要等待粗粒度锁的完成.
由于 innodb 的支持行级锁, 所以意向锁不会阻塞全表扫描以外的任何请求, 故表级意向锁和行级锁的兼容如下表所示:
查看锁的方式:
- ,show engine innodb status
- ,show full processlist
3, 在 information_schema 库中有三个表可以查看, 分别是 innodb_locks, innodb_trx, innodb_lock_waits.
innodb_trx 表的结构(该表只用来显示当前运行 innodb 事务情况, 不能判断锁的情况):
innodb_locks 表的结构(可以查看锁的情况, 当事务较小时, 用户可以认为的只管判断, 如果事务很大, 则认为判断就不好判断了):
innodb_lock_waits 表的结构:
2.2.2, 一致性非锁定读
一致性非锁定读是 innodb 存储引擎通过多版本控制的方式来读取当前执行时间数据库中行的数据, 如果读取到正在删除或者修改的记录, 这时读取的操作不会等待行锁的释放, 而是直接去读取快照中的数据. 如下图所示:
一致性非锁定读, 是因为不需要等待访问行上的 X 锁的释放.
快照数据只的是该行的以前版本的数据, 通过 undo 段来实现, 而 undo 用来事务中的回滚数据, 因此快照数据没有额外的开销, 此外, 读取数据不要上锁, 因为没有事务对历史数据修改. 一致性非锁定读提高数据库的并发性(这是 innodb 的默认读取方式). 但是在不同的事务隔离级别下, 读取方式不同, 并不是每个事务隔离级别下都采用一致性非锁定读, 就算采用一致性非锁定读, 那还有可能就是快照数据的定义各不相同, 比如快照可以有多个版本, 所以这种技术称为多版本技术, 由此带来的并发控制, 称为多版本并发控制(MVCC)
例如在事务隔离级别
READ COMMITTED 中: 一致性非锁定读总是读取被锁定行的最新一份快照数据;
REPEATABLE READ 中: 一致性非锁定读总是读取事务开始时的行数据版本;
2.2.3, 一致性锁定读
虽然 innodb 在默认情况下会采用一致性非锁定读方式进行读取, 但是某些时候用户也可以显示对数据库读取操作进行加锁以保证数据的逻辑的一致性.
innodb 存储引擎对 select 语句支持两种一致性锁定读的操作:
- select ... for update #对读取行加 X 锁, 其他事务不能对已锁定的行加任何锁
- select ... lock in share mode #对读取行加 S 锁, 其他事务允许加 S 锁, 但是如果是 X 锁, 则会阻塞
未完待续....
2.2.4, 自增长与锁
2.2.5, 外键与锁
三, 锁带来的三个问题
四, 锁的算法
五, 锁的其他状态(阻塞, 死锁)
来源: https://www.cnblogs.com/zsql/p/11509473.html