设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间02 现在时间02 缓存数据 曾经在《火星情报局》 汪涵问粉丝们“你们会喜欢薛之谦多久”粉丝们都大喊“一辈子” 当时的薛之谦就笑着说“你们骗人”结果,你们真的骗人。

曾经在《火星情报局》 汪涵问粉丝们“你们会喜欢薛之谦多久”粉丝们都大喊“一辈子” 当时的薛之谦就笑着说“你们骗人”结果,你们真的骗人。 -- 我好像在哪见过你

查看: 695|回复: 0

MySQL自增锁(Auto-Increment Lock) 的原理使用

[复制链接]

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:23
  • 打卡月天数:0
  • 打卡总奖励:272
  • 最近打卡:2025-03-29 18:52:13
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
296
主题
266
精华
0
金钱
1147
积分
612
注册时间
2023-2-11
最后登录
2025-5-31

发表于 2025-5-31 06:44:39 | 显示全部楼层 |阅读模式
1. 背景与动机:为什么需要自增锁?

在 MySQL 中,自增列(
  1. AUTO_INCREMENT
复制代码
)通常用于生成表的主键或唯一标识符,每次插入新行时会自动生成一个递增的整数值。自增列的生成过程必须保证多个事务并发插入时,生成的值不会冲突,因此涉及到并发控制。
为了确保自增值的生成是线程安全的,InnoDB 存储引擎使用了 自增锁(Auto-Increment Lock) 来保护自增值的生成过程。这种锁机制用于防止多个事务同时生成相同的自增值,同时需要在高并发情况下保持高性能。

2. 自增锁的分类

自增锁在 MySQL 中的实现分为两种模式:

  • 表级锁(Table-Level Locking):传统的自增锁模式,整个表在生成自增值时加锁,直到插入操作完成。
  • 轻量级的互斥锁(Mutex):为了优化并发性能,InnoDB 后续引入了更高效的方式,通过轻量级的互斥锁控制自增值的生成,而不必锁定整个表。
MySQL 中自增锁的策略可以通过以下系统变量配置:

    1. innodb_autoinc_lock_mode
    复制代码
    :控制自增锁的模式,有三种值:
    1. 0
    复制代码
    (传统模式):使用表级锁,确保每次插入一个自增值。
    1. 1
    复制代码
    (连续模式):通过互斥锁生成自增值,插入操作可以并发执行。
    1. 2
    复制代码
    (无锁模式):允许批量插入时预先分配自增值,不使用锁。

3. 自增锁的工作机制

MySQL 中自增锁的核心目标是确保自增列在并发插入时的唯一性和连续性。以下是自增锁的具体机制:

  • 单行插入:对于单条插入操作,自增锁确保每个事务获取唯一的自增值。根据锁模式,自增值可能会被锁定直到插入完成(在传统模式下)。
  • 批量插入:对于批量插入(如
    1. INSERT INTO ... SELECT
    复制代码
    1. LOAD DATA
    复制代码
    ),InnoDB 会分配一批自增值,并保证事务插入的行使用连续的自增值范围。
自增锁的具体实现根据
  1. innodb_autoinc_lock_mode
复制代码
的设置而变化:

  • 传统模式 (
    1. innodb_autoinc_lock_mode = 0
    复制代码
    ):

    • 生成自增值时使用表级锁,保证每个插入操作依次获得自增值,且在并发场景下避免了任何冲突。
    • 插入过程中,表上的其他自增操作会被阻塞,直到当前事务完成。

  • 连续模式 (
    1. innodb_autoinc_lock_mode = 1
    复制代码
    ):

    • InnoDB 使用轻量级的互斥锁控制自增值生成,只锁定自增值生成的操作,不锁定整个表。插入操作可以并发执行,因此相比传统模式有更高的性能。
    • 生成自增值后,互斥锁立即释放,允许其他事务并发执行插入。

  • 无锁模式 (
    1. innodb_autoinc_lock_mode = 2
    复制代码
    ):

    • 允许批量插入操作预先分配自增值,而不使用锁机制。每个事务在开始插入时获得一组连续的自增值,即使事务中途回滚或失败,这些自增值也不会回退。
    • 该模式在并发批量插入时具有最佳性能,但可能会导致自增值不连续。


4. 自增锁的底层原理与 InnoDB 的实现

自增锁的实现依赖于 InnoDB 存储引擎的锁管理模块以及内部的互斥锁机制。接下来我们从源代码的角度,剖析 MySQL 如何生成自增值并确保线程安全。

4.1 自增值的生成过程

自增值的生成主要通过
  1. row_ins_set_autoinc_fields()
复制代码
函数完成,该函数会根据当前表的状态和插入模式,决定如何分配自增值。在传统模式下,它需要加锁,以保证只有一个事务能够获取下一个自增值。
  1. void row_ins_set_autoinc_fields(
  2.     row_prebuilt_t* prebuilt,  // 表结构
  3.     trx_t* trx                // 当前事务
  4. ) {
  5.     // 检查自增字段
  6.     if (table->autoinc_field) {
  7.         // 生成自增值的逻辑
  8.         // 如果需要锁,则加锁
  9.         mutex_enter(&dict_table_autoinc_mutex);
  10.         
  11.         // 获取并更新自增值
  12.         table->autoinc_field->value++;
  13.         
  14.         // 释放互斥锁
  15.         mutex_exit(&dict_table_autoinc_mutex);
  16.     }
  17. }
复制代码
在上面的代码中,
  1. mutex_enter()
复制代码
  1. mutex_exit()
复制代码
是用来控制自增值生成的互斥锁。在高并发场景下,轻量级的互斥锁能够比表级锁更好地优化性能。

4.2 自增锁的表级锁实现

  1. innodb_autoinc_lock_mode = 0
复制代码
(传统模式)时,InnoDB 使用表级锁来保护自增值的生成。
  1. lock_table()
复制代码
函数会对整个表加锁,确保只有一个事务能够执行插入操作:
  1. void lock_table(
  2.     dict_table_t* table,   // 表结构
  3.     ulint lock_mode,       // 锁类型
  4.     trx_t* trx             // 当前事务
  5. ) {
  6.     // 传统模式下,给表加 AUTO-INC 锁
  7.     if (lock_mode == LOCK_AUTO_INC) {
  8.         // 加锁逻辑
  9.         lock_rec_lock_table();
  10.     }
  11. }
复制代码
在表级锁的保护下,InnoDB 确保每次插入都严格按照顺序生成自增值,避免冲突。但这种方式也会导致并发性能下降,因为在表锁释放之前,其他事务必须等待。

4.3 轻量级互斥锁的实现

对于
  1. innodb_autoinc_lock_mode = 1
复制代码
  1. innodb_autoinc_lock_mode = 2
复制代码
,InnoDB 主要使用互斥锁保护自增值生成。互斥锁的开销比表级锁小得多,插入操作只在生成自增值时加锁,随后立即释放锁,允许其他事务并发执行。
互斥锁由 InnoDB 的内部锁管理模块控制,相关代码在
  1. trx0trx.cc
复制代码
文件中:
  1. void mutex_enter(mutex_t* mutex) {
  2.     // 互斥锁进入
  3.     os_mutex_enter(mutex);
  4. }

  5. void mutex_exit(mutex_t* mutex) {
  6.     // 互斥锁退出
  7.     os_mutex_exit(mutex);
  8. }
复制代码
当事务请求自增值时,InnoDB 仅在自增值生成过程中加锁,并在生成完毕后立刻释放锁。这种方式显著提升了并发性能,因为大多数事务不会被阻塞。

4.4 自增值的缓存与分配

为了进一步提升性能,InnoDB 还会将自增值保存在缓存中,避免每次插入都访问磁盘。例如,当批量插入时,InnoDB 可以一次性分配一批自增值,然后逐步使用。相关逻辑由
  1. row_ins_get_autoinc()
复制代码
函数实现:
  1. void row_ins_get_autoinc(
  2.     dict_table_t* table,
  3.     ulint num_rows,       // 插入的行数
  4.     trx_t* trx            // 当前事务
  5. ) {
  6.     // 获取缓存的自增值
  7.     autoinc_val = table->autoinc_field->value;
  8.    
  9.     // 为批量插入分配自增值
  10.     for (i = 0; i < num_rows; i++) {
  11.         autoinc_val++;
  12.         // 更新表的自增值
  13.         table->autoinc_field->value = autoinc_val;
  14.     }
  15. }
复制代码
这种缓存机制使得批量插入操作能够获得一组连续的自增值,并在高并发情况下进一步提升性能。

5. 自增锁在事务隔离级别中的表现

自增锁在不同事务隔离级别下有不同表现:

  • 在 可重复读(REPEATABLE READ) 隔离级别下,自增值在事务提交前不会影响其他事务,因此即使事务回滚,自增值也不会回退。
  • 在 读提交(READ COMMITTED) 隔离级别下,每个事务都可以看到最新的自增值,因此自增值始终是递增的。
此外,无论在什么隔离级别下,自增值一旦分配给某个事务,即使该事务回滚,自增值也不会被重新分配。这是为了避免不同事务在回滚后获取相同的自增值。

总结:


  • 自增锁的主要目的是确保自增值在并发插入时唯一且递增。
  • 三种自增锁模式:传统模式(表级锁)、连续模式(轻量级互斥锁)和无锁模式(批量分配自增值),每种模式适用于不同的并发场景。
  • 互斥锁和表级锁的机制在源码中通过
    1. mutex_enter()
    复制代码
    1. lock_table()
    复制代码
    等函数实现,自增值的生成由
    1. row_ins_set_autoinc_fields()
    复制代码
    控制。
  • 批量插入和缓存机制提高了自增值生成的效率,特别是在高并发的场景下,通过提前分配自增值提升性能。
自增锁的灵活机制使 MySQL 在处理大规模并发插入时,既能保持自增值的唯一性,又能通过不同的锁策略在性能和一致性之间取得平衡。
到此这篇关于MySQL自增锁(Auto-Increment Lock) 的原理使用的文章就介绍到这了,更多相关MySQL 自增锁内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表