CoderLi

V1

2022/11/28阅读:23主题:极客黑

Mysql replace into

CREATE TABLE `t` (
  `id` int(11NOT NULL AUTO_INCREMENT,
  `age` int(11DEFAULT NULL,
  `msg` varchar(10DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_age` (`age`)
ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert into t (age, msg) values (1,'aaa'),(2,'bbb'),(3,'ccc');

id 为自增主键、age 为 唯一键

微信公众号:CoderLi
微信公众号:CoderLi

尝试在主数据库执行 replace into

replace into t (age, msg) values (1'111');

因为 age 为 1 已经存在了

微信公众号:CoderLi
微信公众号:CoderLi

所以这里会先执行 delete 然后再执行 insert 、那么则会导致 AUTO_INCREMENT=5 了

但是对于 binlog 来说、仅仅是产生了一条 update 语句。

微信公众号:CoderLi
微信公众号:CoderLi

这样子的话、会导致从数据库那边的 AUTO_INCREMENT 还是 4

微信公众号:CoderLi
微信公众号:CoderLi

主从切换、新主插入失败

我们现在直接看下最新的数据

微信公众号:CoderLi
微信公众号:CoderLi
微信公众号:CoderLi
微信公众号:CoderLi

我们可以看到主数据现在的 AUTO_INCREMENT 的值为 18 、是符合预期的

我们再看看从数据库

微信公众号:CoderLi
微信公众号:CoderLi

可以看到从数据库现在的 AUTO_INCREMENT 为 13 、是比主数据看落后的

现在我们直接将主数据库杀掉、从数据库成为新主、然后尝试 replace into 或者 insert into (不设置 id 的值)

微信公众号:CoderLi

那么会报错主键冲突、插入失败、AUTO_INCREMENT 变为 14

一直直到 AUTO_INCREMENT 的值为 18

正常情况下、insert 失败 AUTO_INCREMENT 是不会变化的

如果在这个过程中、我们指定 id 的值、那么 AUTO_INCREMENT 就会变成 id + 1(这个跟正常情况是一样的)

小结一下

  • insert 成功 AUTO_INCREMENT 会取当前 insert 的 id 的值 +1
  • 正常情况下 insert 失败不会导致 AUTO_INCREMENT 变化
  • 新主 AUTO_INCREMENT 落后于表中最大值时、即使是失败也会导致 AUTO_INCREMENT+1

生产上试过主从切换后、replace into 一直插入失败 、最终的结果是 DBA 手动指定自增列的值、该值为当前表中的最大值、才将 AUTO_INCREMENT 的值回归到正常的值。因为新主当时 AUTO_INCREMENT 的值已经落后很多了、插入一直失败、业务受到影响。

当然重启新主也可以重置 AUTO_INCREMENT

建表时可以指定 AUTO_INCREMENT值,不指定时默认为1,这个值表示当前自增列的起始值大小,如果新插入的数据没有指定自增列的值,那么自增列的值即为这个起始值。对于InnoDB表,这个值没有持久到文件中。而是存在内存中(dict_table_struct.autoinc)。那么又问,既然这个值没有持久下来,为什么我们每次插入新的值后, show create table t1看到AUTO_INCREMENT值是跟随变化的。其实show create table t1是直接从dict_table_struct.autoinc取得的(ha_innobase::update_create_info)。

以上测试对insert into .. on duplicate key update语句同样效果

insert into ... on duplicate key update 会产生死锁问题(看下面的链接)、没有验证过

replace into 这个 bug 在 Mysql 5.7 中存在、但是在 mysql 8.0 的时候已经被修复了

在mysql8.0版本中不仅将AUTO_INCREMENT值做了持久化,且在做更新操作时,如果表上的自增列被更新为比auto_increment更大的值,auto_increment值也将被更新。

神奇的是 inert into ... on duplicate key update AUTO_INCREMENT 的问题还是没有被修复

https://mckobe23.github.io/2016/07/22/replace-autoincrement/

https://yangwuyuan.com/2019/05/10/REPLACE%E6%93%8D%E4%BD%9C%E5%AF%BC%E8%87%B4%E4%B8%BB%E4%BB%8E%E5%BA%93AUTO-INCREMENT%E4%B8%8D%E4%B8%80%E8%87%B4%E7%9A%84%E5%88%86%E6%9E%90/#REPLACE%E6%93%8D%E4%BD%9C%E5%AF%BC%E8%87%B4AUTO-INCREMENT%E5%80%BC%E4%B8%8D%E4%B8%80%E8%87%B4

https://www.cnblogs.com/better-farther-world2099/articles/11737376.html

分类:

后端

标签:

后端

作者介绍

CoderLi
V1