自增不再简单:深入探索MySQL自增ID的持久化之道

news2024/9/24 23:24:16

概述

MySQL中的自增特性估计大家或多或少都是用过。一张表中只能由一个自增字段,通常我们会把它设置为主键,但是随着大家系统越来越分布式,为了一些性能和可扩展性问题,大家目前选择更多的都是分布式ID(雪花算法、UUID,Redis ID, Leaf)。

但是我觉得还是有必要谈一下自增变量为什么要持久化,或许可以为大家以后设计一些系统作为参考。

自增使用

我们先来看看MySQL自增的使用,自增可以在CREATE TABLE和ALTER TABLE使用:

  1. 建表时指定自增
  2. 修改列为自增

建表时指定自增

建表时指定自增列:


create table trade_user(
    id int not null auto_increment primary key,
    name varchar(20) not null default '' comment 'name'
)comment='trade user';

COPY

file

修改列为自增


create table trade_user1(
    id int not null primary key,
    name varchar(20) not null default '' comment 'name'
)comment='trade user';

ALTER TABLE trade_user1 modify id INT NOT NULL auto_increment;

COPY

file

自增模式

表中的自增列有一个专用的锁:AUTO-INC锁,这个锁保证并发场景下没有问题。

AUTO-INC锁,这个锁有几种模式,MySQL 8默认的模式为交错模式,我们来查看下MySQL 8默认的锁模式:


SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';

COPY

file

我们看到Value为2,2是什么?来查个表:

自增锁模式备注
0“传统”模式为每个语句获取表级自增锁,并在语句结束时释放。
1“连续”模式在查询执行的第一次自增ID的生成时获取表级自增锁,并在语句结束时释放。多个并发的自增语句可以同时获取ID并执行。
2“交错”模式只在自增ID需要的时候获取行级的自增锁。这种方式可以大大降低锁的竞争,提高并发性能,但可能会因事务的回滚导致自增ID的不连续。

默认模式

MySQL版本默认值自增锁模式
5.10“传统”模式
5.1 – 5.71“连续”模式
8.02“交错”模式

自增问题

交错自增锁的问题是什么?我们来看看官方的解释:

The default setting is 2 (interleaved) as of MySQL 8.0, and 1 (consecutive) before that. The change to interleaved lock mode as the default setting reflects the change from statement-based to row-based replication as the default replication type, which occurred in MySQL 5.7. Statement-based replication requires the consecutive auto-increment lock mode to ensure that auto-increment values are assigned in a predictable and repeatable order for a given sequence of SQL statements, whereas row-based replication is not sensitive to the execution order of SQL statements.

持久化

遇到了什么问题需要持久化?我们来看个MySQL的bug,bug链接:MySQL Bugs: #199: Innodb autoincrement stats los on restart
这个bug大概描述了MySQL交错模式自增导致的问题,复现步骤:

  1. 创建一个名为“a”的表,其id字段设置为自增字段。
  2. 向表中插入三条记录,到此为止,生成的id值分别为1, 2, 3。
  3. 删除id=3的记录,在表中再次插入一条记录,新记录的id值为4,因此当前表中的id值为1, 2, 4。
  4. 删除id=4的记录,此时MySQL服务器重启。
  5. 重启后,向表中再次插入一条记录,新插入的记录的id值变为了3,这就是AUTO_INCREMENT字段生成重复值的情况。

根据描述,这个问题可能导致的问题是复制中断,因为在主从复制中,主库和从库的AUTO_INCREMENT值可能会不同,从而导致主从数据不一致。

没有持久化自增值之前怎么得到自增值

这个我们自己思考下就可以想到:首先自增变量肯定要放到内存里面,并且与表有一一对应关系,然后自增变量要存储到某个地方以便下次服务启动时读取。

MySQL的思路基本和上面差不多,MySQL的自增变量恢复遵循以下步骤:

  1. 首先,表的自增值肯定是要放到内存中的
  2. 其次, 我们需要思考哪儿有这个自增值:就是表字段
  3. 然后,MySQL通过查询表的元数据来定位和获取自增字段的最大值。
  4. 最后,MySQL执行一条SQL就可以获取了

SELECT MAX(auto_increment_column) FROM table

COPY

例如,要查询’trade_user’表中’id’字段的最大值,可以使用以下SQL:


select max(id) from trade_user

COPY

持久化之后自增ID放到哪儿了?

放到了information_schema数据字典中了,如果你要查询你表的当前的自增ID值,执行下面这条SQL:


SELECT `AUTO_INCREMENT`
FROM `information_schema`.`tables`
WHERE `table_schema` = 'blog'
AND `table_name` = 'trade_user1';

COPY

file

再进一步,到底怎么存储的

先看MySQL官方怎么说:

In MySQL 8.0, this behavior is changed. The current maximum auto-increment counter value is written to the redo log each time it changes and saved to the data dictionary on each checkpoint. These changes make the current maximum auto-increment counter value persistent across server restarts.

这个大概意思就是:
MySQL会把自增计数器的当前最大值写入redo log,并在每次检查点时保存到数据字典中,这样就完成了自增计数器的持久化。

数据库重启了以后怎么恢复?因为重启可能是因为崩溃,最新的自增值还没有写入到数据字典中,那么就得这么干了:

  1. 数据库启动的时候先从数据字典中获取元数据,把表的自增ID加载到内存中
  2. 服务器重放redo log中的所有事务,然后把自增ID修改为redo log中的值

总结

从MySQL自增值持久化问题以及解决方案,我们从中可以学习到:

  1. 数据持久化和一致性的重要性
  2. 设计系统时要考虑到异常情况,如果没有考虑到异常情况,出一些意料之外的问题你会很蒙蔽
  3. 全局唯一ID的重要性,这个ID非常重要,要是混乱了,你的饭碗可能瞬间都没了,而且后面的就刷库吧

参考

1. MySQL自增变量持久化 – FOF编程网

创作不易,难免会有点错误或者可读性问题,请大家理解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nextcloud激活被锁用户

Nextcloud激活用户 如果docker下没有安装sudo 和 vim执行下面命令,安装了则跳过 #进入docker内部 #更新apt-get apt-get update #安装sudo apt-get install sudo #安装vim apt-get install vim 修改下面文件内容,否则执行occ命令可能报错 进入上面查询…

吴恩达深度学习笔记:浅层神经网络(Shallow neural networks)3.1-3.5

目录 第一门课:神经网络和深度学习 (Neural Networks and Deep Learning)第三周:浅层神经网络(Shallow neural networks)3.1 神经网络概述(Neural Network Overview)3.2 神经网络的表示(Neural Network Representation…

搭建 canal 监控mysql数据到RabbitMQ

项目需求: 使用canal监控mysql某个库某个表,或者多个库,多个表---- update/inster/create 操作, 系统版本mysql版本java版本canal版本rabbitMQ版本Rocky 9.2MySQL 8.0.26openjdk 11.0.221.1.6rabbitmq-server 3.12.4 mysql 配置…

JMeter元件作用域和执行顺序

JMeter元件作用域和执行顺序 元件的基本介绍基本元件总结 作用域的基本介绍作用域的原则元件执行顺序Jmeter第一个案例: Jmeter三个重要组件(重点)线程组特点线程组分类线程组的属性案例分析 HTTP请求案例一(使用HTTP请求路径来传…

Mysql如何创建存储过程,Navicat如何创建存储过程

一、 通过sql创建和调用存储过程 DELIMITER // CREATE PROCEDURE no_parameters_procedure_name() BEGIN -- 代码块 select 测试无参存储过程; END //DELIMITER ;call no_parameters_procedure_name();二、 通过Navicat界面创建存储过程 格式为 CREATE DEFINERroot% PROCE…

cas学习2:idea里搭建cas项目

在上篇中介绍了cas服务在tomcat中怎么启动的及某j集成cas,这篇讲下idea怎么集成cas成一个项目,为后续的定制化开发做好铺垫。 1.下载CAS 模板 Overlay Template,我这里使用 Apereo CAS 5.3 版本,JDK需要1.8 地址:Git…

目前国内体验最佳的AI问答助手:kimi.ai

文章目录 简介图片理解长文档解析 简介 kimi.ai是国内初创AI公司月之暗面推出的一款AI助手,终于不再是四字成语拼凑出来的了。这是一个非常存粹的文本分析和对话工具,没有那些东拼西凑花里胡哨的AIGC功能,实测表明,这种聚焦是对的…

基于nodejs+vue家装一体化平台python-flask-django-php

提高现下家装一体化平台的准确度,同时降低经济波动带来的不良影响,希望本文能对广大学者的研究提供参考。 前端技术:nodejsvueelementui, Express 框架于Node运行环境的Web框架, 语言 node.js 框架:Express 前端:Vue.js 数据库&am…

使用git下载github/gitee仓库部分或单个文件的方法

前言 有些时候在github或者gitee仓库中我们只需要下载整个项目中的我门需要的那一部分文件夹或文件就行了,不需要下载所有的项目。这样可以节省很多流量和时间 步骤 1.建立一个新的 git 本地仓库 这里我在D:\test中初始化 命令: git init2.在本地仓…

使用JMeter进行梯度压测

使用JMeter进行梯度压测 梯度压测配置如下: 使用线程:5,然后循环5000次,共2.5万个样本使用线程:10,然后循环5000次,共5万个样本使用线程:15,然后循环5000次,共7.5万个样本使用线程:20&#xff…

Excel·VBA数组分组问题

看到一个帖子《excel吧-数据分组问题》,对一组数据分成4组,使每组的和值相近 目录 代码思路1,分组形式、可分组数代码1代码2代码2举例 2,数组所有分组形式举例 这个问题可以转化为2步:第1步,获取一组数据…

【msyql】mysqldump: 未找到命令...

使用mysqldump备份数据库出现错误提示: mysqldump: 未找到命令... 执行的命令如下: mysqldump -uroot -proot --databases db_user > /home/backups/databackup.sql 解决方法 确认mysql是否安装 查看mysql版本 mysql --version 查找mysql安装路…

STM32学习笔记(6_5)- TIM定时器的输出捕获原理

无人问津也好,技不如人也罢,都应静下心来,去做该做的事。 最近在学STM32,所以也开贴记录一下主要内容,省的过目即忘。视频教程为江科大(改名江协科技),网站jiangxiekeji.com 现在开…

在for循环加判断条件当条件都满足时,同时显现的解决方法

一、代码示例 function fu(s) {str ;ste ;console.log(s);let Things s;for (let i 0; i < Things.length; i) {if (Things[i].pid kk) {console.log(Things[i].pid);ste <div class"commodity_nei"><div class"zxc_pic"><div cl…

【Java初阶(五)】类和对象

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; 目录 1. 前言2.面向对象的认识3.类的认识4. 类的实例化4.1什么是实例化4.2类和对象的说明 5.this引用6.对象初始化6.1 构造方法 7.static关键字8.代码块8.1 …

6.使用个人用户登录域控的成员服务器,如何防止个人用户账号的用户策略生效?

&#xff08;1&#xff09;需求&#xff1a; &#xff08;2&#xff09;实战配置步骤 第一步:创建新的策略-并编辑策略 第二步&#xff1a;将策略应用到服务器处在OU 第三步&#xff1a;测试 &#xff08;1&#xff09;需求&#xff1a; 比如域控&#xff0c;或者加入域的…

CUDA从入门到放弃(六):CUDA内存结构(Memory Hierarchy)

CUDA从入门到放弃&#xff08;六&#xff09;&#xff1a;CUDA内存结构&#xff08;Memory Hierarchy&#xff09; CUDA线程在执行过程中可以从多个内存空间访问数据。每个线程都有私有的局部内存。每个线程块具有共享内存&#xff0c;该内存对所有线程块内的线程可见&#xf…

磁盘文件系统实际操练,解释到bit

author: hjjdebug date: 2024年 03月 25日 星期一 17:50:02 CST description: 磁盘文件系统实际操练,解释到bit文章目录 0. 为什么需要磁盘文件系统.1. 磁盘文件系统的任务是什么?2. 空白磁盘是什么? 空白磁盘数据长什么样?3. 格式化磁盘都干了什么? 格式化后的磁盘长什么…

YoloV8改进策略:Neck改进|ECA-Net:用于深度卷积神经网络的高效通道注意力|多种改进方法|附结构图

摘要 本文使用ECA-Net注意力机制加入到YoloV8中。我尝试了多种改进方法&#xff0c;并附上改进结果&#xff0c;方便大家了解改进后的效果&#xff0c;为论文改进提供思路。 论文&#xff1a;《ECA-Net&#xff1a;用于深度卷积神经网络的高效通道注意力》 arxiv.org/pdf/19…

“一根盲杖,扫清前进道路”视障人士关爱行动中

近期&#xff0c;红枫林义警服务发展中心联合暨南街道社工站&#xff0c;面向暨南街道辖区内的视障人群&#xff0c;开展了一系列服务&#xff0c;送去了我们的关爱。 首先&#xff0c;我们成功为视障人群链接到了价值1万的爱心物资&#xff0c;捐赠仪式即为本次我们关爱行动的…