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

对MySQL锁、事务、MVCC的简单认识

mysql教程栏目介绍对MySQL锁、事务、MVCC的简单认识。

mysql教程栏目介绍对MySQL锁、事务、MVCC的简单认识。

MySQL 是如何实现事务的 ACID 的?

事务具有 ACID 四大特性,那么 MySQL 是如何实现事务的这四个属性的呢?

  • 原子性 要么全部成功,要么全部失败。MySQL是通过记录 undo_log 的方式来实现的原子性。undo_log 即回滚日志,在真正的SQL执行之前先将 undo_log 写入磁盘,然后再对数据库的数据进行操作。如果发生异常或回滚,就可以依据 undo_log 进行反向操作,恢复数据在事务执行之前的样子。

  • 持久性 事务一旦被正常提交,它对数据库的影响就应该是永久的。此时即使系统崩溃,修改的数据也不会丢失。InnoDB 作为 MySQ L的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB 提供了缓存(Buffer Pool),作为访问数据库的缓冲:当从数据库读取数据时,会首先从 Buffer Pool 中读取,如果 Buffer Pool 中没有,则从磁盘读取后放入 Buffer Pool ;当向数据库写入数据时,会首先写入 Buffer Pool,Buffer Pool 中修改的数据会定期刷新到磁盘中。

    这样的设计也带来了相应的问题:如果数据提交了,这时数据还在缓冲池里(还没刷盘),此时MySQL宕机、断电了怎么办?数据会不会丢失?

    答案是不会,MySQL 通过 redo_log 的机制,保证了持久性。redo_log 即重做日志,简单说就是当数据修改时,除了修改 Buffer Pool 中的数据,还会在 redo_log 记录这次操作;当事务提交时,会调用 fsync 接口对 redo_log 进行刷盘。如果MySQL宕机,重启时可以读取 redo_log 中的数据,对数据库进行恢复。

  • 隔离性

    隔离性是 ACID 里面最复杂的一个,这里面涉及到隔离级别的概念,一共有四个

    • Read uncommitted
    • Read committed
    • Repeatable read
    • Serializable

    简单说隔离级别就是规定了:一个事务中数据的修改,哪些事务之间可见,哪些不可见。而隔离性就是要管理多个并发读写请求的访问顺序。

    MySQL 对于隔离性的具体实现我们后面会展开说。

  • 一致性

    通过回滚、恢复和在并发环境下的隔离做到一致性。

事务并发可能导致的问题

通过上个问题我知道单条 DDL 执行也会被当成一个事务自动提交,那么无论是多条SQL并发,还是多个自己手动组织的包含多条SQL的事务并发,都会导致事务并发问题。

具体来说有:

  • 脏写 (一个事务提交的数据覆盖了另一个事务未提交的数据)
  • 脏读 (一个事务读取到另一个事务未提交的数据)
  • 不可重复读 (重点在于update和delete 一个事务内多次读取的数据不一样)
  • 幻读 (重点在于insert 一个事务内多次读取的记录数不一样)

上面我们提到了事务的隔离级别,MySQL 的所有隔离级别都能保证不产生脏写,所以就剩下脏读、不可重复读和幻读的问题了。

下面具体看下各隔离级别是如何解决或未解决上面这些问题的:

Read uncommitted

未提交读,这个级别在读的过程中不会加任何锁,只在写请求时加锁,所以写操作在读的过程中修改数据,就会造成脏读。也自然会产生不可重复读和幻读。

Read committed

已提交读,与未提交读一样也是读不加锁,写加锁。不一样的是利用了 MVCC 机制避免了脏读的问题,同样会有不可重复读和幻读的问题。关于 MVCC 我们后面会详细说。

Repeatable read

MySQL 默认的隔离级别,在这个级别 MySQL利用两种方式解决问题

  1. 读写锁 读读并行时加读锁,读读是共享锁的。 只要有写请求就加写锁,这样读写是串行的。 读取数据时加锁,其它事务无法修改这些数据。所以不会产生不可重复读。 修改删除数据时也要加锁,其它事务无法读取这些数据,所以不会产生脏读。 第一种方式就是我们常说的 “悲观锁”,数据在整个事务处理过程中处于锁定状态,比较保守,性能开销比较大。
  2. MVCC (后面讲)

此外还利用了Next-Key锁 在一定程度上解决了幻读的问题。关于这个我们后面再说。

Serializable

在该隔离级别下事务都是串行顺序执行的。 如果禁用了自动提交,则 InnoDB 会将所有普通的 SELECT 语句隐式转换为 SELECT ... LOCK IN SHARE MODE。即给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。

MVCC

Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory

翻译过来就是:多版本并发控制(MCC或MVCC)是一种并发控制方法,通常被数据库管理系统用来提供对数据库的并发访问,并以编程语言来实现事务存储。

简单来说就是数据库用来控制并发的一种方法。每个数据库对于 MVCC 的实现可能不一样。

以我们常用的 MySQL 来说,MySQL 的 InnoDB 引擎实现了 MVCC 。

MVCC 能解决什么问题

从上面的定义我们能看出,MVCC 主要解决事务并发时数据一致性的问题

InnoDB 是如何实现的 MVCC

下面这个图来自《高性能MySQL》(第3版)

版本链

之前我们讲过 undo_log 的概念,每条 undo日志都有一个 roll_pointer 属性,那么所有的版本都会被 roll_pointer 属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。

ReadView

通过隐藏列和版本链,MySQL 可以将数据恢复到指定版本;但是具体要恢复到哪个版本,则需要根据 ReadView 来确定。所谓 ReadView,是指事务(记做事务A)在某一时刻给整个事务系统(trx_sys)打快照,之后再进行读操作时,会将读取到的数据中的事务 id 与 trx_sys 快照比较,从而判断数据对该 ReadView 是否可见,即对事务A是否可见。

至此我们发现 MVCC 就是基于隐藏字段、undo_log 链和 ReadView 来实现的。

Read committed 中的 MVCC

前面我们讲过 Read committed 隔离级别中使用 MVCC 解决脏读问题。 这里我参考了两篇文章:

  • https://cloud.tencent.com/developer/article/1150633
  • https://cloud.tencent.com/developer/article/1150630

InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的版本号小于或是等于事务的系统版本 号),这样可以确保数据读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或修改过的。因此不会产生脏读

Read committed 隔离级别下出现不可重复读是由于 read view 的生成机制造成的。在 Read committed 级别下,只要当前语句执行前已经提交的数据都是可见的。在每次语句执行的过程中,都关闭 read view, 重新创建当前的一份 read view。这样就可以根据当前的全局事务链表创建 read view 的事务区间。简单说就是在 Read committed 隔离级别下,MVCC 在每次 select 时生成一个快照版本,所以每次 select 都会读到不同的版本数据,所以会产生不可重复读

Repeatable read 中的 MVCC

Repeatable read 隔离级别解决了不可重复读的问题,一个事务中多次读取不会出现不同的结果,保证了可重复读。前文中我们说 Repeatable read 有两种实现方式,一种是悲观锁的方式,相对的 MVCC 就是乐观锁的方式。

Repeatable read 隔离级别能解决不可重复读根本原因其实就是 read view 的生成机制和 Read committed 不同。

  • Read committed :只要是当前语句执行前已经提交的数据都是可见的。
  • Repeatable read :只要是当前事务执行前已经提交的数据都是可见的。

不像 Read committed,在 Repeatable read 的隔离级别下,创建事务的时候,就生成了当前的 global read view,一直维持到事务结束。这样就能实现可重复读。

幻读与 Next-Key 锁

当前读与快照读

通过 MVCC 机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!对于这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库当前版本数据的方式,叫当前读 (current read) 参考[3]

  • 快照读:就是select
    • select * from table ….;
  • 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。
    • select * from table where ? lock in share mode;
    • select * from table where ? for update;
    • insert;
    • update ;
    • delete;

解决幻读

为了解决当前读中的幻读问题,MySQL事务使用了 next-key lock 。

以上就是对MySQL锁、事务、MVCC的简单认识的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 本文详细介绍了如何通过多种编程语言(如PHP、JSP)实现网站与MySQL数据库的连接,包括创建数据库、表的基本操作,以及数据的读取和写入方法。 ... [详细]
  • 使用Vultr云服务器和Namesilo域名搭建个人网站
    本文详细介绍了如何通过Vultr云服务器和Namesilo域名搭建一个功能齐全的个人网站,包括购买、配置服务器以及绑定域名的具体步骤。文章还提供了详细的命令行操作指南,帮助读者顺利完成建站过程。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 根据最新发布的《互联网人才趋势报告》,尽管大量IT从业者已转向Python开发,但随着人工智能和大数据领域的迅猛发展,仍存在巨大的人才缺口。本文将详细介绍如何使用Python编写一个简单的爬虫程序,并提供完整的代码示例。 ... [详细]
  • 本文探讨了如何在 PHP 的 Eloquent ORM 中实现数据表之间的关联查询,并通过具体示例详细解释了如何将关联数据嵌入到查询结果中。这不仅提高了数据查询的效率,还简化了代码逻辑。 ... [详细]
  • 本文详细介绍了MySQL数据库中的Bin Log和Redo Log,阐述了它们在日志记录机制、应用场景以及数据恢复方面的区别。通过对比分析,帮助读者更好地理解这两种日志文件的作用和特性。 ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
author-avatar
晨曦--雨荷
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有