热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于mysql:深入剖析-MySQL-自增锁

之前的文章把InnoDB中的所有的锁都介绍了一下,包含意向锁、记录锁自增锁巴拉巴拉的。然而前面我本人回过头去看的时候发现,对自增锁的介绍竟然才短短的一段。

之前的文章把 InnoDB 中的所有的锁都介绍了一下,包含意向锁、记录锁…自增锁巴拉巴拉的。然而前面我本人回过头去看的时候发现,对自增锁的介绍竟然才短短的一段。

其实自增锁(AUTO-INC Locks)这块还是有很多值得探讨的细节,例如在并发的场景下,InnoDB 是如何保障该值正确的进行自增的,本章就专门来简略讨论一下 InnoDB 中的自增锁。

什么是自增锁

之前咱们提到过,自增锁是一种比拟非凡的表级锁。并且在事务向蕴含了 AUTO_INCREMENT 列的表中新增数据时就会去持有自增锁,假如事务 A 正在做这个操作,如果另一个事务 B 尝试执行 INSERT语句,事务 B 会被阻塞住,直到事务 A 开释自增锁。

这怎么说呢,说他对,然而他也不齐全对。

行为与限度

其实下面说的那种阻塞状况只是自增锁行为的其中一种,能够了解为自增锁就是一个接口,其具体的实现有多种。具体的配置项为 innodb_autoinc_lock_mode ,通过这个配置项咱们能够扭转自增锁中运行的一些细节。

并且,自增锁还有一个限度,那就是被设置为 AUTO_INCREMENT 的列必须是索引,或者该列是索引的一部分(联结索引),不过这个限度对于大部分开发场景下并没有什么影响。

毕竟咱们的基操不就是把 id 设置为 AUTO_INCREMENT 吗。

锁模式

其实在 InnoDB 中,把锁的行为叫做锁模式可能更加精确,那具体有哪些锁模式呢,如下:

  • 传统模式(Traditional)
  • 间断模式(Consecutive)
  • 穿插模式(Interleaved)

别离对应配置项 innodb_autoinc_lock_mode 的值0、1、2.

看到这就曾经晓得为啥下面说不精确了,因为三种模式下,InnoDB 对并发的解决是不一样的,而且具体抉择哪种锁模式跟你以后应用的 MySQL 版本还有关系。

在 MySQL 8.0 之前,InnoDB 锁模式默认为间断模式,值为1,而在 MySQL 8.0 之后,默认模式变成了穿插模式。至于为啥会扭转默认模式,前面会讲。

传统模式

传统模式(Traditional),说白了就是还没有锁模式这个概念时,InnoDB 的自增锁运行的模式。只是前面版本更新,InnoDB 引入了锁模式的概念,而后 InnoDB 给了这种以前默认的模式一个名字,叫——传统模式。

传统模式具体是咋工作的?

咱们晓得,当咱们向蕴含了 AUTO_INCREMENT 列的表中插入数据时,都会持有这么一个非凡的表锁——自增锁(AUTO-INC),并且当语句执行完之后就会开释。这样一来能够保障单个语句内生成的自增值是间断的。

这样一来,传统模式的弊病就天然裸露进去了,如果有多个事务并发的执行 INSERT 操作,AUTO-INC的存在会使得 MySQL 的性能略有降落,因为同时只能执行一条 INSERT 语句。

间断模式

间断模式(Consecutive)是 MySQL 8.0 之前默认的模式,之所以提出这种模式,是因为传统模式存在影响性能的弊病,所以才有了间断模式。

在锁模式处于间断模式下时,如果 INSERT 语句可能提前确定插入的数据量,则能够不必获取自增锁,举个例子,像 INSERT INTO 这种简略的、能提前确认数量的新增语句,就不会应用自增锁,这个很好了解,在自增值上,我能够间接把这个 INSERT 语句所须要的空间流进去,就能够继续执行下一个语句了。

然而如果 INSERT 语句不能提前确认数据量,则还是会去获取自增锁。例如像 INSERT INTO ... SELECT ... 这种语句,INSERT 的值来源于另一个 SELECT 语句。

间断模式的图和穿插模式差不多

穿插模式

穿插模式(Interleaved)下,所有的 INSERT 语句,蕴含 INSERTINSERT INTO ... SELECT ,都不会应用 AUTO-INC 自增锁,而是应用较为轻量的 mutex 锁。这样一来,多条 INSERT 语句能够并发的执行,这也是三种锁模式中扩展性最好的一种。

并发执行所带来的副作用就是单个 INSERT 的自增值并不间断,因为 AUTO_INCREMENT 的值调配会在多个 INSERT 语句中来回穿插的执行。

长处很明确,毛病是在并发的状况下无奈保证数据一致性,这个上面会探讨。

穿插模式缺点

要理解缺点是什么,还得先理解一下 MySQL 的 Binlog。Binlog 个别用于 MySQL 的数据复制,艰深一点就是用于主从同步。在 MySQL 中 Binlog 的格局有 3 种,别离是:

  • Statement 基于语句,只记录对数据做了批改的SQL语句,可能无效的缩小binlog的数据量,进步读取、基于binlog重放的性能
  • Row 只记录被批改的行,所以Row记录的binlog日志量一般来说会比Statement格局要多。基于Row的binlog日志十分残缺、清晰,记录了所有数据的变动,然而毛病是可能会十分多,例如一条update语句,有可能是所有的数据都有批改;再例如alter table之类的,批改了某个字段,同样的每条记录都有改变。
  • Mixed Statement和Row的联合,怎么个结合法呢。例如像alter table之类的对表构造的批改,采纳Statement格局。其余的对数据的批改例如updatedelete采纳Row格局进行记录。

如果 MySQL 采纳的格局为 Statement ,那么 MySQL 的主从同步实际上同步的就是一条一条的 SQL 语句。如果此时咱们采纳了穿插模式,那么并发状况下 INSERT 语句的执行程序就无奈失去保障。

可能你还没看出问题在哪儿,INSERT 同时穿插执行,并且 AUTO_INCREMENT 穿插调配将会间接导致主从之间同行的数据主键 ID 不同。而这对主从同步来说是灾难性的。

换句话说,如果你的 DB 有主从同步,并且 Binlog 存储格局为 Statement,那么不要将 InnoDB 自增锁模式设置为穿插模式,会有问题。其实主从同步的过程远比上图中的简单,之前我也写过具体的MySQL主从同步的文章,感兴趣能够先去看看。

而起初,MySQL 将日志存储格局从 Statement 变成了 Row,这样一来,主从之间同步的就是实在的行数据了,而且 主键ID 在同步到从库之前曾经确定了,就对同步语句的程序并不敏感,就躲避了下面 Statement 的问题。

基于 MySQL 默认 Binlog 格局从 StatementRow 的变更,InnoDB 也将其自增锁的默认实现从间断模式,更换到了效率更高的穿插模式

鱼和熊掌

然而如果你的 MySQL 版本依然默认应用间断模式,但同时又想要进步性能,该怎么办呢?这个其实得做一些取舍。

如果你能够判定你的零碎后续不会应用 Binlog,那么你能够抉择将自增锁的锁模式从间断模式改为穿插模式,这样能够进步 MySQL 的并发。并且,没有了主从同步,INSERT 语句在从库乱序执行导致的 AUTO_INCREMENT 值不匹配的问题也就天然不会遇到了。

总结

你可能会说,为啥要理解这么深?有啥用?

其实还真有,例如在业务中你有一个须要执行 几十秒 的脚本,脚本中不停的调用屡次 INSERT,这时就问你这个问题,在这几十秒里,会阻塞其余的用户应用对应的性能吗?

如果你对自增锁有足够的理解,那么这个问题将会迎刃而解。

本篇文章已放到我的 Github github.com/sh-blog 中,欢送 Star。微信搜寻关注【SH的全栈笔记】,回复【队列】获取MQ学习材料,蕴含根底概念解析和RocketMQ具体的源码解析,继续更新中。

如果你感觉这篇文章对你有帮忙,还麻烦点个赞关个注分个享留个言


推荐阅读
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文介绍了通过mysql命令查看mysql的安装路径的方法,提供了相应的sql语句,并希望对读者有参考价值。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • MySQL外键1对多问题的解决方法及实例
    本文介绍了解决MySQL外键1对多问题的方法,通过准备数据、创建表和设置外键关联等步骤,实现了用户分组和插入数据的功能。详细介绍了数据准备的过程和外键关联的设置,以及插入数据的示例。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
author-avatar
好人langren_840
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有