深入研究MySQL的自增锁

本文涉及的产品
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介: ySQL的自增锁是指在使用自增主键(Auto Increment)时,为了保证唯一性和正确性,系统会对自增字段进行加锁。这样可以确保同时插入多条记录时,每条记录都能够获得唯一的自增值。

2.5 自增锁

MySQL的自增锁是指在使用自增主键(Auto Increment)时,为了保证唯一性和正确性,系统会对自增字段进行加锁。这样可以确保同时插入多条记录时,每条记录都能够获得唯一的自增值。

2.5.1 表的插入数据方式

我们之前在表中插入数据都是用最基本的insert,但insert语句的用法用很多,另外MySQL还提供replace语句,允许对表中的数据进行替换;

  • insert用法:
drop table if exists t3;
CREATE TABLE `t3`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT=1;
insert into t3 values(1,20);
insert into t3 values(2,25);
drop table if exists t4;
CREATE TABLE `t4`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT=1;
-- 插入记录,如果存在这条记录就报错(主键唯一)
insert into t4 values(10,20);
insert into t4 values(11,20),(12,21),(13,22);
insert into t4 set id=14,age=25;
insert into t4 select * from t3;
  • replace用法:
delete from t4;
-- 如果没有这条记录就新增,有这条记录就修改
replace into t4 values(1,20);  
replace into t4 set id=10,age=100 ;
replace into t4 select * from t3;

2.5.1 insert的不同类型

1)Simple inserts

简单插入模式

  • 示例:
insert into table_name values(xxx);
  • 特点:可以提前确定要插入的行数

2)Bulk inserts

批量插入模式,包含insert...select、replace select、load data等语句;

  • 示例:
insert into t4 select * from t3;
replace into t4 select * from t3;

Tips:load data属于海量数据插入,暂时不演示

  • 特点:事先不知道要插入的行数,以及所需的自动增量值的数量

3)Mixed-mode

该模式也属于Simple Inserts

  • 示例:
insert into table_name values(xxxx),(xxxx),(xxxx);
  • 特点:为一些(但不是全部)新行指定自动增量值

2.5.2 自增锁原理

1)插入原理

MySQL自增锁的实现机制是使用了一个名为"auto-increment lock"的互斥锁。当使用INSERT语句插入一条新记录时,MySQL会自动为自增字段加锁,防止其他并发的插入操作同时获取相同的自增值。这个锁是在内部实现的,不需要用户手动创建或管理。

自增锁确保了插入记录的唯一性和正确性,避免了并发插入产生冲突。但同时也会带来一些性能上的影响,因为并发插入操作需要等待锁的释放。因此,在高并发的场景下,可能需要考虑使用其他方案来避免自增锁成为瓶颈。

注意:自增锁跟事务无关,即使多个insert语句存在同一个事务中,每次insert都会申请最新的自增锁来获取最新的AUTO_INCREMENT值;自增锁保持到insert语句结束,而不是事务结束;

2)自增锁表锁

需要注意的是,自增锁是基于表级别的,而不是行级别的。这意味着在同一时刻针对于同一张表只能有一个线程在插入记录(前提是需要increment来分配id),并且每个表都有一个自己独立的自增锁。

2.5.3 自增锁的模式

和自增锁相关的一个参数为(5.1.22版本之后加入)innodb_autoinc_lock_mode:可以设定3个值,0,1,2

show variables like 'innodb_autoinc_lock_mode';

  • 0:traditional(传统模式):每次insert都会产生表级别的自增锁,能够绝对保证insert的插入顺序,但并发能力较弱;
  • 1:consecutive(连续模式):对于Simple Inserts能够产生一个轻量级的页面锁来保证insert的连续插入;对于Bulk Inserts无法确定插入的行数时采用表级别自增锁来保证insert的连续插入;
  • 2:interleaved(交叉模式):不采用表锁,来一个insert处理一个,并发能力最高,但可能会造成insert分配的id顺序不一致;

Tips:参数只控制InnoDB引擎的设置,所有MyISAM均为traditional ,每次均会进行表锁。只有Innodb会视参数不同而产生不通的锁。

1)traditional(传统模式)

在传统模式下,不管是在执行Simple inserts还是Bulk inserts时每个insert获取自增锁时都会触发表锁,在某个insert没有释放表锁之前其他线程/进程均不可获取自增锁;虽然传统模式保证了多个insert插入的连续性但实际上并发插入属于串行化,性能较低;

Tips:再次说明,自增锁是执行insert时获取auto_increment值时才会申请,获取到auto_increment值时就会立即释放,跟事务无关;

2)consecutive(连续模式)

在连续模式下,InnoDB会根据当前执行的insert语句来判断是否使用表级别自增锁。这也是InnoDB的默认值;

  • Simple inserts:InnoDB能够预先知道要插入的行数,因此产生的自增锁只会锁住对应的那些id(页锁),避免表级别的自增锁
  • Bulk Inserts:InnoDB无法预知要插入的行,触发表级别自增锁

【Simple Inserts】

【Bulk Inserts】

3)interleaved(交叉模式)

在交叉模式下,所有的insert语句都不会使用自增锁(悲观锁),而是采用一个轻量级的mutex(乐观锁),来一个insert立即处理,在生成insert语句完毕后检查id是否被其他线程/进程使用,如果已经被使用则重新获取id;这样一来,多条 INSERT 语句可以并发的执行,因此交叉模式并发量最高,但对于同一个语句来说它所得到的auto_increment值可能不是连续的。

  • 交叉模式示意图:

【模拟交叉模式并发插入情况】

步骤①:Thread-01线程执行insert获取到auto_increment值为10

步骤②:与此同时Thread-02线程也获取到10

步骤③:然后又回到Thread-01线程对auto_increment值+1,此时auto_increment为11

步骤④:然后Thread-02线程也对auto_increment+1,此时auto_increment为12

步骤⑤:Thread-01线程校验id值是否被其他线程使用过,校验结果:未被其他线程使用过,执行插入

步骤⑥:Thread-01线程校验id值是否被其他线程使用过,校验结果:已经被其他线程使用过,本次操作取消;

最终Thread-01线程先将auto_increment值写入插入字段中,Thread-02线程将auto_increment写入字段中发现该字段已经被其他线程使用过,因此本次操作取消;但auto_increment值已经变为12;下一次执行insert的线程获取auto_increment值将会获取到12,auto_increment为11这一次就这样跳过了;

【交叉模式的注意事项】

由于交叉模式所带来的id不连续问题,在搭建有MySQL主从复制的架构并且binlog日志格式为SBR时会出现主从数据不一致问题;

原因:当Master接收高并发量的insert语句时会将insert语句记录到binlog日志中,这些binlog日志被发送到Slave时Slave将会并发执行这些SQL语句,很有可能导致Slave执行这些语句的顺序和当初Master执行的顺序一致,导致主从分配的id不一致,因此在MySQL主从复制时从服务器应禁止使用交叉模式;

2.5.4 自增步长控制

一般我们在创建表的时候id起始值为1,通过AUTO_INCREMENT可以设置其值;

drop table if exists t3;
CREATE TABLE `t3`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT=1;
-- 在创建表后也可以通过SQL语句修改auto_increment
alter table t3 auto_increment=20;

自增幅度由以下两个参数进行控制:

-- 自增的步长
set auto_increment_increment=2;     -- 默认1

可以通过函数获取最后一个插入的id:

select last_insert_id();

【测试】

session-01

session-02

begin;

begin;

insert into t3 values(null,1);

insert into t3 values(null,1);

rollback;

commit;

最终session-02插入的那条记录id为2;

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
存储 SQL 关系型数据库
深入MySQL锁机制:原理、死锁解决及Java防范技巧
深入MySQL锁机制:原理、死锁解决及Java防范技巧
|
3天前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制
|
9天前
|
SQL 存储 关系型数据库
"MySQL增列必锁表?揭秘InnoDB在线DDL,让你的数据库操作飞一般,性能无忧!"
【8月更文挑战第11天】在数据库领域,MySQL凭借其稳定高效的表现深受开发者喜爱。对于是否会在给数据表添加列时锁表的问题,MySQL的行为受版本、存储引擎等因素影响。从5.6版起,InnoDB支持在线DDL,可在改动表结构时保持表的可访问性,避免长时间锁表。而MyISAM等则需锁表完成操作。例如,在使用InnoDB的表上运行`ALTER TABLE users ADD COLUMN email VARCHAR(255);`时,通常不会完全锁表。虽然在线DDL提高了灵活性,但复杂操作或大表变更仍可能暂时影响性能。因此,进行结构变更前应评估其影响并择机执行。
29 6
|
7天前
|
存储 SQL 关系型数据库
MySQL中的update操作与锁机制
本文探讨MySQL中`UPDATE`操作的自动加锁机制及其对数据一致性的保障作用。尤其在InnoDB存储引擎下,系统会在涉及索引的更新操作中加行锁或间隙锁,防止多事务并发修改同一条记录。通过福利码兑换系统的实例展示,当线程A开启事务更新库存时,线程B试图更新相同记录会被阻塞,直至线程A提交。此外,文章还介绍了乐观锁及版本号控制等策略进一步提升并发性能的方法。作者:小明爱吃火锅,来源:稀土掘金。
|
19天前
|
SQL 关系型数据库 MySQL
(八)MySQL锁机制:高并发场景下该如何保证数据读写的安全性?
锁!这个词汇在编程中出现的次数尤为频繁,几乎主流的编程语言都会具备完善的锁机制,在数据库中也并不例外,为什么呢?这里牵扯到一个关键词:高并发,由于现在的计算机领域几乎都是多核机器,因此再编写单线程的应用自然无法将机器性能发挥到最大,想要让程序的并发性越高,多线程技术自然就呼之欲出,多线程技术一方面能充分压榨CPU资源,另一方面也能提升程序的并发支持性。
|
19天前
|
SQL 算法 关系型数据库
(十)全解MySQL之死锁问题分析、事务隔离与锁机制的底层原理剖析
经过《MySQL锁机制》、《MySQL-MVCC机制》两篇后,咱们已经大致了解MySQL中处理并发事务的手段,不过对于锁机制、MVCC机制都并未与之前说到的《MySQL事务机制》产生关联关系,同时对于MySQL锁机制的实现原理也未曾剖析,因此本篇作为事务、锁、MVCC这三者的汇总篇,会在本章中补全之前空缺的一些细节,同时也会将锁、MVCC机制与事务机制之间的关系彻底理清楚。
|
26天前
|
存储 关系型数据库 文件存储
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
30 2
|
7天前
|
存储 SQL 关系型数据库
MySQL意向锁是什么?
意向锁用于协调InnoDB存储引擎中的行锁与表锁,避免全表扫描判断行锁的存在,提升性能。主要包括意向共享锁(IS)与意向排他锁(IX),分别在请求行级共享(S)锁与排他(X)锁前加于表级。意向锁自动管理,无需用户干预。例如,事务A锁定一行时先加IS锁,B事务可加IX锁但不能直接加表级X锁。意向锁与行级S/X锁兼容,仅与表级S/X锁冲突。这确保了锁机制高效且减少冲突。
|
21天前
|
关系型数据库 MySQL 数据处理
mysql锁及锁出现总结
mysql锁及锁出现总结
20 0
|
1月前
|
关系型数据库 MySQL 数据库
mysql,归零,无法自动排序,删除id,表单的数据没有从零开始出现怎样解决?删除数据仍然从删除的地方该怎样解决?表单的数据没有从2开始,而是从之前的删除的序号开始自增。
mysql,归零,无法自动排序,删除id,表单的数据没有从零开始出现怎样解决?删除数据仍然从删除的地方该怎样解决?表单的数据没有从2开始,而是从之前的删除的序号开始自增。

相关产品

  • 云数据库 RDS MySQL 版