共计 2241 个字符,预计需要花费 6 分钟才能阅读完成。
本篇内容介绍了“MySQL 中 InnoDB 锁机制分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一 前言
本文介绍另外两种锁 Insert Intention Locks 和 AUTO-INC Locks
二 常见的锁类型
2.1 根据锁持有的时间粒度,分为
1. 内存级别:类似 mutex,很快释放
2. 语句级别:statement 结束,释放
3. 事务级别:transaction 提交或者回滚才释放
4. 会话级别:session 级别,连接断开才释放
2.2 AUTO-INC lock
AUTO-INC lock 是一个特殊的表级锁,当一个事务向含有自增字段的表插入数据时,该事务会获取一个 AUTO-INC lock,其他事务必须等待直到已经获取锁的 insert 语句结束。因此, 多个并发事务不能同时获取同一个表上面的 AUTO-INC lock, 如果持有 AUTO-INC 锁太长时间可能会影响到数据库性能 (比如 INSERT INTO t1… SELECT … FROM t2 这类语句) 或者死锁.
鉴于 AUTO-INC 锁的特性,MySQL 5.1.22 通过新增参数 innodb_autoinc_lock_mode 来控制自增序列的算法。该参数可以设置为 0,1,2.
在学习 innodb_autoinc_lock_mode 之前,我们先了解 insert 语句的类型
1 Simple inserts
能够事先确定具体行数的 insert 语句,比如 insert into tab values()…(); replace 等等。INSERT … ON DUPLICATE KEY UPDATE 和还有子查询的 insert 语句除外。
2 Bulk inserts
和 Simple inserts 对立,事先不能确定插入行数的 insert/replace 语句,insert … select ;replace …select; load data into table .. 这种情况下 Innodb 在执行具体的行的时候 会为每一行单独分配一个 auto_increment 值。
3 Mixed-mode inserts
该情形是 Simple inserts 模式中,有些 insert 指定了 自增字段的具体值,有些没有指定。比如:
INSERT INTO t1 (c1,c2) VALUES (1, a), (NULL, b), (5, c), (NULL, d
INSERT … ON DUPLICATE KEY UPDATE
接下来我们再看 MySQL 对 auto_increment 的优化模式。
innodb_autoinc_lock_mode=0,是传统的方式。InnoDB 会在分配前给表加上 AUTO_INC 锁,并在 SQL 结束时释放掉。该模式保证了在 STATEMENT 复制模式下,备库执行类似 INSERT … SELECT 这样的语句时的一致性,因为这样的语句在执行时无法确定到底有多少条记录,只有在执行过程中不允许别的会话分配自增值,才能确保主备一致。
很显然这种锁模式非常影响并发插入的性能,但却保证了一条 SQL 内自增值分配的连续性。
innodb_autoinc_lock_mode=1,这个是 InnoDB 的默认值。该模式下对于 Simple inserts,InnoDB 会先加一个 autoinc_mutex 锁,然后去判断表上是否有别的线程加了 LOCK_AUTO_INC 锁,如果有的话,释放 autoinc_mutex,并使用传统的加锁模式。否则,在预留本次插入需要的自增值之后,就快速的将 autoinc_mutex 释放掉。很显然,对于普通的并发 INSERT 操作,都是无需加 LOCK_AUTO_INC 锁的。因此该模式提高了系统并发性;
innodb_autoinc_lock_mode=2,这种模式下只在分配时加个 mutex 即可,很快就释放,不会像值为 1 那样在某些场景下会退化到传统模式。因此设为 2 不能保证批量插入的复制安全性。
2.3 Insert Intention Locks
插入意向锁是 gap 锁的一种,只是针对 insert。当并发事务多条 insert 插入同一个 GAP, 如果他们不是插入同一行记录,会话之间并不会相互等待。例如索引记录删 有 12,17 两个记录,两个会话同时插入记录 13,15,他们会分别为 (12,17) 加上 GAP 锁,但相互之间并不冲突(因为插入的记录不冲突)。
当向某个数据页中插入一条记录时,总是会调用函数 lock_rec_insert_check_and_lock 进行锁检查(构建索引时的数据插入除外),会去检查当前插入位置的下一条记录上是否存在锁对象,这里的下一条记录不是指的物理连续,而是按照逻辑顺序的下一条记录。
如果下一条记录上不存在锁对象:若记录是二级索引上的,先更新二级索引页上的最大事务 ID 为当前事务的 ID;直接返回成功。
如果下一条记录上存在锁对象,就需要判断该锁对象是否锁住了 GAP。如果 GAP 被锁住了,并判定和插入意向 GAP 锁冲突,当前操作就需要等待,加的锁类型为 LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,并进入等待状态。但是插入意向锁之间并不互斥。这意味着在同一个 GAP 里可能有多个申请插入意向锁的会话。
“MySQL 中 InnoDB 锁机制分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!