mysql 主键自增的范围_MySQL自增主键知识点总结

mysql 主键自增的范围_MySQL自增主键知识点总结自增主键自增值的存储 MyISAM 引擎将当前自增值存储在表数据文件中 InnoDB 引擎在 5 7 及之前将当前自增值存储在内存中 MySQL 重启时从表中查询自增列最大值 步长作为当前自增值 InnoDB 引擎在 8 0 及之后版本中将自增值变动记录存储在 redolog 中 重启 MySQL 后根据 redolog 恢复之前的自增值 自增值的变化执行插入语句时 如果自增列的值不指定 或指定为 0 或 null 则插入时将表

自增主键

自增值的存储

MyISAM引擎将当前自增值存储在表数据文件中。

InnoDB引擎在5.7及之前将当前自增值存储在内存中,MySQL重启时从表中查询自增列最大值+步长作为当前自增值。

InnoDB引擎在8.0及之后版本中将自增值变动记录存储在redo log中,重启MySQL后根据redo log恢复之前的自增值。

自增值的变化

执行插入语句时,如果自增列的值不指定,或指定为0或null,则插入时将表当前自增值填入该列,并增长自增值(当前自增值+步长)。

执行插入语句时,如果自增列指定了某个值,则使用指定的值。然后从当前自增值开始循环+步长,选择第一个大于指定值的数值作为新的当前自增值。

即:如果设置自增从1开始,步长10,则自增值依次是1、11、21。如果插入了一条自增列为37的记录,则下次获取到的自增值是41,因为41是21之后第一个大于37的自增值。

— 查看自增值与自增步长

SHOW VARIABLES LIKE ‘auto_inc%’;

— 设置自增步长,重启MySQL后失效

SET @@auto_increment_increment = 10;

— 查询上次获取到的自增ID

SELECT last_insert_id();

自增列不连续的情况发生事务回滚时。因为每次取自增值都会变化,事务回滚时并不会撤回已经被取走的自增值,因此当发生事务回滚时会发生自增列不连续的情况。

发生唯一键冲突时。发生唯一键冲突之前,首先会获取当前自增值填入自增列,然后由于发生唯一键冲突,导致插入失败,但此时自增值已经发生了变化,会导致不连续。

insert…select语句执行时。insert…select语句执行时如果插入多行,会批量申请自增值,第一次申请1个,第二次申请2个,第三次申请4个,第N次申请2^(N-1)个。所以如果第N次申请了多个值,但是没有用掉的话,也会造成自增列不连续。

比如insert…select插入了4行,自增列自增值从1开始。首先申请1个,然后申请2个,再申请3个。此时共申请了7个自增值,但是只插入了5行数据,表中自增列最大值为5,但当前自增值是8,下次插入的行自增列会是8。

是所有插入失败都会导致不连续吗?不是。如果是列的值超出范围,这个是在插入之前检查的,此时还没有申请自增值,所以不会改变当前自增值,所以不会造成不连续

自增列的锁

自增列的锁并非事务锁,申请完拿到自增值后立即释放,而不是等到事务提交。

MySQL5.0之前,自增锁是与语句相关的,如果在插入语句中用到自增锁,会等到语句执行完成后才释放。

MySQL5.1及之后,添加了一个参数innodb_autoinc_lock_mode配置,用于控制自增锁行为:值为0,表示采用MySQL5.0之前的策略,语句执行完成后释放;

值为1,普通insert语句在申请用完之后立即释放;批量插入语句如insert多个values或insert…select语句,还是要等到语句执行完成后释放;

值为2,所有申请自增主键的动作都是申请用完后释放。

默认值是1。

自增列导致的主从数据不一致问题

当binlog_format设置为STATMENT时,binlog中记录的是每次执行的修改数据SQL。此时如果插入数据未指定自增列值而是使用自动获取的话,可能发生主从数据不一致问题。

如:自增值从1开始,步长1。事务A插入两条数据,自增列值分别为1、2。

此时开启事务B,插入一条数据,然后回滚。

然后事务A再插入一条数据,自增列值为4。

提交事务A。

此时主库中数据为1、2、4。而同步到从库后执行插入语句,插入的数据为1、2、3,主从数据不一致。

解决思路:避免从库自动得到自增列ID。

解决办法:插入时指定ID。

将binlog_fomat设置为row。

自增列值用完了

会继续使用上一次生成的自增值。也就是自增值不再增长。

last_insert_id()问题

查询上一次递增ID的值:

select last_insert_id();当在不同事务中各执行一条插入语句时,返回的是各自事务中生成的ID;

当在同一个事务中多次执行插入语句时,会返回最后一次插入语句的ID;

当在一个SQL语句中批量插入多条数据时,返回的是批量插入的第一条数据的ID;

当在不同事务中各执行一条插入语句时,返回的是各自事务中生成的ID。

mysql> begin;

Query OK, 0 rows affected (0.05 sec)

mysql> insert into t(c, d) values(5, 6);

Query OK, 1 row affected (0.11 sec)

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 8 |

+——————+

1 row in set (0.06 sec)

mysql> begin;

Query OK, 0 rows affected (0.05 sec)

mysql> insert into t(c, d) values(6, 4);

Query OK, 1 row affected (0.05 sec)

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 9 |

+——————+

1 row in set (0.06 sec)

当在同一个事务中多次执行插入语句时,会返回最后一次插入语句的ID。

mysql> begin;

Query OK, 0 rows affected (0.05 sec)

mysql> insert into t(c, d) values(6, 4);

Query OK, 1 row affected (0.05 sec)

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 9 |

+——————+

1 row in set (0.06 sec)

mysql> insert into t(c, d) values(76, 1);

Query OK, 1 row affected (0.06 sec)

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 14 |

+——————+

1 row in set (0.05 sec)

当在一个SQL语句中批量插入多条数据时,返回的是批量插入的第一条数据的ID。

mysql> insert into t(c, d) values(76, 1);

Query OK, 1 row affected (0.06 sec)

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 14 |

+——————+

1 row in set (0.05 sec)

mysql> insert into t(c, d) values(22, 1), (23, 1), (24, 1);

Query OK, 3 rows affected (0.05 sec)

Records: 3 Duplicates: 0 Warnings: 0

mysql> select last_insert_id();

+——————+

| last_insert_id() |

+——————+

| 15 |

+——————+

1 row in set (0.05 sec)

mysql> commit;

Query OK, 0 rows affected (0.06 sec)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228349.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午7:14
下一篇 2026年3月16日 下午7:14


相关推荐

  • checkbox选中和不选中 jqu_jquery checkbox 选中不选中

    checkbox选中和不选中 jqu_jquery checkbox 选中不选中展开全部$(function(){//动态绑定默认状态//$(“#ck”).attr(“checked”,true)//选中//$(“#ck”).attr(“checked”,false)//未选中//点击判断选中还是未选中$(“#ck”).click(function(){if($(this).is(“:checked”)){alert(“选中”);}else{alert…

    2022年6月30日
    24
  • java文件保存到服务器_java文件保存至服务器

    java文件保存到服务器_java文件保存至服务器importjava io ByteArrayOut importjava io File importjava io FileOutputSt importjava io InputStream importjava net HttpURLConne importjava net URL publicclassI

    2026年3月19日
    3
  • pages enableEventValidation 事件的机制处理

    pages enableEventValidation 事件的机制处理回发或回调参数无效。在配置中使用或在页面中使用<%@PageEnableEventValidation=”true”%>启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用ClientScriptManager.RegisterForEventValidation方法来注册回发或回调数据以…

    2022年7月24日
    10
  • word2vec原理简述[通俗易懂]

    word2vec原理简述[通俗易懂](原创)word2vec是将单词转为向量,并为后续应用机器学习的算法做准备。经典的模型有两种,skip-gram和cbow,其中,skip-gram是给定输入单词来预测上下文,而cbow相反,是给定上下文来预测输入单词。下面主要介绍skip-gram:1.skip-gram训练词对skip-gram首先设定所谓一个值(skip_window),作为一个单词选取它的上下文的单词…

    2022年5月16日
    31
  • AI Agent全解析:从概念到落地的技术指南

    AI Agent全解析:从概念到落地的技术指南

    2026年3月16日
    3
  • endnote转化成纯文本后_EndNote X7如何去掉域代码生成纯文本文件

    endnote转化成纯文本后_EndNote X7如何去掉域代码生成纯文本文件满意答案czpunk2016.08.17采纳率:58%等级:9已帮助:2963人现在很多杂志都要求作者提供电子文稿。格式化后的文稿含有大量域代码,有可能与杂志社的软件不兼容,因此提交前需要去掉文稿里的域代码。方法是从Word的工具栏里进入“EndNote7.0”子菜单选择点击“RemoveFieldCodes”,出现一个提示框告诉你“该操作将创建一个新的去掉了所有域代码的Word文档,…

    2022年5月28日
    58

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号