MySQL 数据库 InnoDB 自增锁

总的来说,InnoDB 共有七种类型的锁:
(1) 共享/排它锁(Shared and Exclusive Locks)
(2) 意向锁(Intention Locks)
(3) 记录锁(Record Locks)
(4) 间隙锁(Gap Locks)
(5) 临键锁(Next-key Locks)
(6) 插入意向锁(Insert Intention Locks)
(7) 自增锁(Auto-inc Locks)

下面将结合案例,剖析 InnoDB 的自增锁

案例

MySQL,InnoDB,默认的隔离级别(RR),假设有数据表:t(id AUTO_INCREMENT, name);
数据表中有数据:

  • shenjian
  • zhangsan
  • lisi

事务A先执行,还未提交:
insert into t(name) values(xxx);

事务B后执行:
insert into t(name) values(ooo);

问:事务B会不会被阻塞?

分析

InnoDB在RR隔离级别下,能解决幻读问题,上面这个案例中:
(1) 事务A先执行insert,会得到一条(4, xxx)的记录,由于是自增列,故不用显示指定id为4,InnoDB会自动增长,注意此时事务并未提交;
(2) 事务B后执行insert,假设不会被阻塞,那会得到一条(5, ooo)的记录;

此时,并未有什么不妥,但如果

(3) 事务A继续insert:
insert into t(name) values(xxoo);
会得到一条(6, xxoo)的记录。
(4) 事务A再select:
select * from t where id>3;
得到的结果是:
4, xxx
6, xxoo

那么,就不可能查询到5的记录,再RR的隔离级别下,不可能读取到还未提交事务生成的数据。这对于事务A来说,就很奇怪了,对于AUTO_INCREMENT的列,连续插入了两条记录,一条是4,接下来一条变成了6。

自增锁

自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。

与此同时,InnoDB 提供了 innodb_autoinc_lock_mode 配置,可以调节与改变该锁的模式与行为。

上面的案例,假设不是自增列,又会是什么样的情形呢?

t(id unique PK, name);
数据表中有数据:
10, shenjian
20, zhangsan
30, lisi

事务A先执行,在10与20两条记录中插入了一行,还未提交:
insert into t values(11, xxx);

事务B后执行,也在10与20两条记录中插入了一行:
insert into t values(12, ooo);

你可能感兴趣的:(MySQL 数据库 InnoDB 自增锁)