自增锁模式

在MYSQL 5.1.22版本前,自增列使用AUTO_INC Locking方式来实现,即采用一种特殊的表锁机制来保证并发插入下自增操作依然是串行操作,为提高插入效率,该锁会在插入语句完成后立即释放,而不是插入语句所在事务提交时释放。该设计并发性能太差,尤其在大批量数据在一条语句中插入时(INSERT SELECT ), 会导致该语句长时间持有这个“表锁”,从而阻塞其他事务的插入操作。

在MYSQL 5.1.22版本开始,InnoDB存储引使用一种轻量级互斥锁(Mutex)来控制自增列增长,并提供innodb_autoinc_lock_mode参数来控制。

自增长方式可分为下面四类:

.INSERT-LIKE:指所有的插入语句,比如 INSERT、REPLACE、INSERT…SELECT、REPLACE…SELECT,LOAD DATA等。
.Simple insert:指在插入前就能确定插入行数的语句,包括INSERT、REPLACE,不包含INSERT…ON DUPLICATE KEY UPDATE这类语句。
.Bulk inserts:指在插入前不能确定得到插入行的语句。如INSERT…SELECT,REPLACE…SELECT,LOAD DATA.
.Mixed-mode inserts:指其中一部分是子增长的,有一部分是确定的。

innodb_autoinc_lock_mode参数取值

.innodb_autoinc_lock_mode=0 传统锁定模式, 5.1.22之前的方式,也就是所有INSERT-LIKE操作都用AUTO-inc locking。
.innodb_autoinc_lock_mode= 连续锁定模式,这个参数是5..22之后出现的也是之后的默认值,对于SIMPLE INSERT,使用轻量级互斥锁,对于BULK INSERT,使用AUTO-inc locking。
.innodb_autoinc_lock_mode= 交错锁定模式,指不管什么情况都使用轻量级互斥的锁,效率最高,但是复制只能使用row-basereplication,因为statement-base replication会出现问题。

当innodb_autoinc_lock_mode=1时,"Simple insert"操作能在插入前知道插入的记录数量,因此无需在整个插入操作过程中持有表级别的AUTO-INC锁,MySQL通过轻量级互斥锁来控制INSERT操作获取自增值的过程,并在INSERT操作获取到自增值后快速释放互斥锁,通过降低锁颗粒度和锁持续周期,实现"Simple insert"操作并发执行。当其他事物对表持有AUTO-INC锁时,"Simple insert"操作也会升级使用AUTO-INC锁并被阻塞。

当innodb_autoinc_lock_mode=1时,在语句复制格式下(BINLOG_FORMAT=STATEMENT),BINLOG中没有记录主库执行过程中获取到的所有自增值及其对应行的信息,要保证"Bulk insert"操作主从复制数据一致就必须保证语句在主库和从库执行时获取到相同自增值,而因此只能通过控制“获取连续自增值”的方式来实现,同时为避免受其他事务插入操作影响,就必须在表级别加锁且保证持有锁至语句结束。

在行复制格式下(BINLOG_FORMAT=ROW),主库BINLOG中保存有记录的所有列信息包括自增列值,因此无需通过AUTO-INC锁来保证主从数据一致。

在MySQL 8.0版本前,参数BINLOG_FORMAT的默认值为STATEMENT,参数innodb_autoinc_lock_mode的默认值为1。

在MySQL 8.0版本后,参数BINLOG_FORMAT的默认值被调整为ROW格式,参数innodb_autoinc_lock_mode的默认值为2。

自增值间隙

在MySQL中,获取自增值的操作是非事务性,获取自增值的操作产生的锁在语句执行过程中或执行完成里便被释放而不会持续到事务提交和回滚,获取到自增值也不会随事务回滚而回滚,因此不能依赖MySQL自增列来实现表中列值连续无间隙。

表中自增列作为代理键,只能用来标识和定位记录,而不应该承载业务逻辑,因此也不建议对自增列值进行显式更新。

AUTO_INC锁导致的死锁

在业务繁忙的表上通过pt-osc进行DDL操作变更时,可能会出现死锁,死锁场景如下:

pt-osc工具执行对tb001执行DDL变更操作,创建临时表_tb001_new来执行变更并拷贝数据,并在tb001上创建增删改三种触发器。

步骤1、事务1执行业务操作对表tb001进行数据更新,对更新记录加排他锁(X)

步骤2、pt-osc的拷贝线程拷贝数据,事务2执行INSERT INTO _tb001_new SELECT FROM tb001 WHERE ... LOCK IN SHARE MODE的操作,先执行INSERT INTO操作申请_tb001_new表上AUTO-INC锁,申请成功

步骤3、事务1更新操作触发表tb0011上update触发器执行中执行REPLACE INTO操作,向表_tb001_new更新插入数据,申请_tb001_new表上AUTO-INC锁,由于事务2持有_tb001_new表上AUTO-INC锁,因此事务1被阻塞。

步骤4、事务2获取_tb001_new表上AUTO-INC锁后,再执行SELECT FROM tb001 WHERE ... LOCK IN SHARE MODE操作,申请某个范围内所有记录上的共享锁(S),由于事务1持有其中一条或多条记录的排他锁(X),导致事务2被阻塞。

步骤5、事务2被阻塞,触发死锁检测,发现事务1和事务2相互等待锁资源形成死锁,挑选事务1或事务2进行事务回滚。

上述死锁解决办法:

1、在行复制格式下(BINLOG_FORMAT=ROW),可以考虑调整参数innodb_autoinc_lock_mode的值为2(非动态参数,需重启服务)

2、通过降低锁冲突概率来降低死锁发生概率:

、在业务低峰期进行DDL变更操作
、优化业务SQL降低单个事务修改记录数
、调整pt-osc单次拷贝操作的数据量

参考资料:

https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_autoinc_lock_mode

MySQL AutoIncrement--自增锁模式的更多相关文章

  1. MySQL自增锁模式innodb_autoinc_lock_mode参数理解调优

    前段时间某数据表运行过程中,出现自增字段突然跳跃式增长的问题,潜心研究发现,问题导致原因可能是因为并发写入导致 于是通过各种途径查阅是因为innodb_autoinc_lock_mode参数设置的不同 ...

  2. 深入剖析 MySQL 自增锁

    之前的文章把 InnoDB 中的所有的锁都介绍了一下,包括意向锁.记录锁...自增锁巴拉巴拉的.但是后面我自己回过头去看的时候发现,对自增锁的介绍居然才短短的一段. 其实自增锁(AUTO-INC Lo ...

  3. Mysql研磨之InnoDB行锁模式

    事务并发带来的一些问题 (1)更新丢失(LostUpdate):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题最后的更新覆盖了由其 ...

  4. mysql 开发进阶篇系列 7 锁问题(innodb锁争用情况及锁模式)

    1 .获取innodb行锁争用情况 1.1 通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况 SHOW STATUS LIKE 'innodb_row_lock%' 通过in ...

  5. MySQL自增锁等待问题解决

    有网友再群里问:在做基准测试时候,批量插入数据时,有很多自增锁等待,我告诉他解决办法: 1.innodb_autoinc_lock_mode=2 2.innodb_autoextend_increme ...

  6. INNODB自增主键的一些问题 vs mysql获得自增字段下一个值

    今天发现 批量插入下,自增主键不连续了....... InnoDB AUTO_INCREMENT Lock Modes This section describes the behavior of A ...

  7. 【MySQL】索引和锁

    前言 本文摘自数据库两大神器[索引和锁] 声明:如果没有说明具体的数据库和存储引擎,默认指的是MySQL中的InnoDB存储引擎 索引 在之前,我对索引有以下的认知: 索引可以加快数据库的检索速度 表 ...

  8. MySql InnoDB中的锁研究

    # MySql InnoDB中的锁研究 ## 1.InnoDB中有哪些锁### 1. 共享和排他(独占)锁(Shared and Exclusive Locks) InnoDB实现标准的行级锁定,其中 ...

  9. MySQL的死锁系列- 锁的类型以及加锁原理

    疫情期间在家工作时,同事使用了 insert into on duplicate key update 语句进行插入去重,但是在测试过程中发现了死锁现象: ERROR 1213 (40001): De ...

随机推荐

  1. python 一般处理

    #!/usr/bin/env python# -*- coding:utf-8 -*-# Author:afei# QQ:97259460# date = 2019/8/29 s_code1=''s_ ...

  2. kubernetes篇 容器用户权限控制

    问题起源 问题起源于一个开发BUG:正常运行一段时间的POD,突然有一天运行报错了,错误是没有操作目录的权限,查其原因,原来是镜像被更新了,镜像添加了操作用户,而被操作的目录(NFS目录)并不具备普通 ...

  3. protobufjs@6.8.8 postinstall: `node scripts/postinstall`

    由于Node.js 版本太低了, 使用最新版用 Node.js =================================== 以下解决方法来源于网络 npm ERR! Windows_NT ...

  4. git 本地删除修改文件后从远程拉取

    单个文件 git checkout a.php 当前目录 git checkout .

  5. 在 Windows 中配置Maven

    访问http://maven.apache.org/ 点击左侧的导航栏,Download 跳转到下载maven的页面,往下滚动,看到 Files 处,选择apache-maven-3.3.9-bin- ...

  6. 创建Observer

    观察者 观察者作用就是监听事件, 然后对这个事件做出响应, 或者说任何响应时间的行为都是观察者 1. 在subscribe()方法中创建监听者 创建观察者最直接的方法就是在Observable的sub ...

  7. 解决IDEA打Jar包找不到或无法加载主类问题

    转自以下博主内容:https://blog.csdn.net/qq_43189115/article/details/99856659 就是因为打包一直提示有问题,网上很多帖子试过没有用,就是这个博主 ...

  8. Linux的.a、.so和.o文件 对比 window下的dll,lib,exe文件

    连续几天终于将一个又一个问题解决了,这里说其中一个问题 描述问题:使用多线程pthread的时候,(我用的IDE,CODEBOLCKS)编译后发现直接弹出窗口,程序还没有被Build..巴拉巴拉,然后 ...

  9. 在nginx环境下搭建https服务,代理到本地web项目

    安装过程略. 1.证书准备 本地调试,可以安装自签名证书,安装方法参考https本地自签名证书添加到信任证书访问 2.修改配置文件 将上面的配置文件拷贝到conf目录,添加或者修改节点如下 http{ ...

  10. mavn jar包依赖冲突解决

    背景:使用maven很方便,但是引入冲突也很常见.后果很严重,各种不明实体找不到,所以需要对jar包的依赖有一个清晰的认识. 查看冲突 参考:用dependency:tree查看maven引入jar包 ...