MySQL - 解读MySQL事务与锁机制

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: MySQL - 解读MySQL事务与锁机制

20200809231924303.png


生猛干货

带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试


事务及其特性


大家都知道 ACID (原子性、一致性、隔离性和持久性)


一个逻辑工作单元要成为事务,在关系型数据库管理系统中,必须满足 4 个特性


  • 原子性 : 事务的所有操作,要么全部完成,要么全部不完成,不会结束在某个中间环节
  • 一致性 : 事务开始之前和事务结束之后,数据库的完整性限制未被破坏
  • 隔离性 : 数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然
  • 持久性 : 事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持


ACID 及它们之间的关系如下图所示,比如 4 个特性中有 3 个与 WAL 有关系,都需要通过 Redo、Undo 日志来保证等。



20200810002034879.png





一致性


首先来看一致性,一致性其实包括两部分内容,分别是约束一致性和数据一致性。


约束一致性:我们应该很容易想到数据库中创建表结构时所指定的外键、Check、唯一索引等约束。可惜在 MySQL 中,是不支持 Check 的,只支持另外两种,所以约束一致性就非常容易理解了。


数据一致性:是一个综合性的规定,或者说是一个把握全局的规定。因为它是由原子性、持久性、隔离性共同保证的结果,而不是单单依赖于某一种技术。


原子性


原子性就是前面提到的两个“要么”,即要么改了,要么没改。也就是说用户感受不到一个正在改的状态。MySQL 是通过 WAL(Write Ahead Log)技术来实现这种效果的。

原子性和 WAL 到底有什么关系呢?


举例来讲,如果事务提交了,那改了的数据就生效了,如果此时 Buffer Pool 的脏页没有刷盘,如何来保证改了的数据生效呢?就需要使用 Redo 日志恢复出来的数据。而如果事务没有提交,且 Buffer Pool 的脏页被刷盘了,那这个本不应该存在的数据如何消失呢?就需要通过 Undo 来实现了,Undo 又是通过 Redo 来保证的,所以最终原子性的保证还是靠 Redo 的 WAL 机制实现的。


隔离性


所谓隔离性,指的是一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对其他的并发事务是隔离的。锁和多版本控制就符合隔离性。


持久性


所谓持久性,就是指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,接下来的操作或故障不应该对其有任何影响。前面已经讲到,事务的原子性可以保证一个事务要么全执行,要么全不执行的特性,这可以从逻辑上保证用户看不到中间的状态。但持久性是如何保证的呢?一旦事务提交,通过原子性,即便是遇到宕机,也可以从逻辑上将数据找回来后再次写入物理存储空间,这样就从逻辑和物理两个方面保证了数据不会丢失,即保证了数据库的持久性。


并发事务控制

单版本控制-锁


锁用独占的方式来保证在只有一个版本的情况下事务之间相互隔离,所以锁可以理解为单版本控制。


在 MySQL 事务中,锁的实现与隔离级别有关系,在 RR(Repeatable Read)隔离级别下,MySQL 为了解决幻读的问题,以牺牲并行度为代价,通过 Gap 锁来防止数据的写入,而这种锁,因为其并行度不够,冲突很多,经常会引起死锁。


多版本控制-MVCC


多版本控制也叫作 MVCC,是指在数据库中,为了实现高并发的数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能看到自己应该看到的数据版本。


那个多版本是如何生成的呢?每一次对数据库的修改,都会在 Undo 日志中记录当前修改记录的事务号及修改前数据状态的存储地址(即 ROLL_PTR),以便在必要的时候可以回滚到老的数据版本。例如,一个读事务查询到当前记录,而最新的事务还未提交,根据原子性,读事务看不到最新数据,但可以去回滚段中找到老版本的数据,这样就生成了多个版本。


多版本控制很巧妙地将稀缺资源的独占互斥转换为并发,大大提高了数据库的吞吐量及读写性能。


原子性实现原理


每一个写事务,都会修改 Buffer Pool,从而产生相应的 Redo 日志,这些日志信息会被记录到 ib_logfiles 文件中。因为 Redo 日志是遵循 Write Ahead Log 的方式写的,所以事务是顺序被记录的。


在 MySQL 中,任何 Buffer Pool 中的页被刷到磁盘之前,都会先写入到日志文件中,这样做有两方面的保证。


如果 Buffer Pool 中的这个页没有刷成功,此时数据库挂了,那在数据库再次启动之后,可以通过 Redo 日志将其恢复出来,以保证脏页写下去的数据不会丢失,所以必须要保证 Redo 先写。

因为 Buffer Pool 的空间是有限的,要载入新页时,需要从 LRU 链表中淘汰一些页,而这些页必须要刷盘之后,才可以重新使用,那这时的刷盘,就需要保证对应的 LSN 的日志也要提前写到 ib_logfiles 中,如果没有写的话,恰巧这个事务又没有提交,数据库挂了,在数据库启动之后,这个事务就没法回滚了。所以如果不写日志的话,这些数据对应的回滚日志可能就不存在,导致未提交的事务回滚不了,从而不能保证原子性,所以原子性就是通过 WAL 来保证的


持久性实现原理


如下图所示,一个“提交”动作触发的操作有:binlog 落地、发送 binlog、存储引擎提交、flush_logs, check_point、事务提交标记等。这些都是数据库保证其数据完整性、持久性的手段。


20200810002915755.png

那这些操作如何做到持久性呢?前面讲过,通过原子性可以保证逻辑上的持久性,通过存储引擎的数据刷盘可以保证物理上的持久性。这个过程与前面提到的 Redo 日志、事务状态、数据库恢复、参数 innodb_flush_log_at_trx_commit 有关,还与 binlog 有关。这里多提一句,在数据库恢复时,如果发现某事务的状态为 Prepare,则会在 binlog 中找到对应的事务并将其在数据库中重新执行一遍,来保证数据库的持久性。


隔离性实现原理


InnoDB 支持的隔离性有 4 种,隔离性从低到高分别为:读未提交、读提交、可重复读、可串行化。


读未提交(RU,Read Uncommitted)。它能读到一个事务的中间过程,违背了 ACID 特性,存在脏读的问题,所以基本不会用到,可以忽略。


读提交(RC,Read Committed)。它表示如果其他事务已经提交,那么我们就可以看到,这也是一种最普遍适用的级别。但由于一些历史原因,可能 RC 在生产环境中用的并不多。


可重复读(RR,Repeatable Read),是目前被使用得最多的一种级别。其特点是有 Gap 锁、目前还是默认的级别、在这种级别下会经常发生死锁、低并发等问题。


可串行化,这种实现方式,其实已经并不是多版本了,又回到了单版本的状态,因为它所有的实现都是通过锁来实现的。


说到隔离性的实现方式,我们通常用 Read View 表示一个事务的可见性。前面讲到 RC 级别的事务可见性比较高,它可以看到已提交的事务的所有修改。而 RR 级别的事务,则没有这个功能,一个读事务中,不管其他事务对这些数据做了什么修改,以及是否提交,只要自己不提交,查询的数据结果就不会变。这是如何做到的呢?


随着时间的推移,读提交每一条读操作语句都会获取一次 Read View,每次更新之后,都会获取数据库中最新的事务提交状态,也就可以看到最新提交的事务了,即每条语句执行都会更新其可见性视图。而反观可重复读,这个可见性视图,只有在自己当前事务提交之后,才去更新,所以与其他事务是没有关系的。


在 RR 级别下,长时间未提交的事务会影响数据库的 PURGE 操作,从而影响数据库的性能,所以可以对这样的事务添加一个监控。


可串行化是通过锁来实现的,所以实际上并不是多版本控制,它的特点也很明显:读锁、单版本控制、并发低。


一致性实现原理


一致性可以归纳为数据的完整性。 数据的完整性是通过其他三个特性来保证的,包括原子性、隔离性、持久性,而这三个特性,又是通过 Redo/Undo 来保证的 ,为了保证数据的完整性,提出来三个特性,这三个特性又是由同一个技术来实现的,所以理解 Redo/Undo 才能理解数据库的本质。


20200810003339509.png

如上图所示,逻辑上的一致性,包括唯一索引、外键约束、check 约束,这属于业务逻辑范畴.


搞定MySQL

https://artisan.blog.csdn.net/article/details/107902378?spm=1001.2014.3001.5502

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
21天前
|
SQL 关系型数据库 MySQL
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
|
1天前
|
存储 SQL 关系型数据库
MySQL 事务
MySQL 事务
|
6天前
|
关系型数据库 MySQL 索引
MySQL 锁机制
MySQL 锁机制
7 0
|
14天前
|
关系型数据库 MySQL 数据库
MySQL锁三部曲:临键、间隙与记录的奇妙旅程
MySQL锁三部曲:临键、间隙与记录的奇妙旅程
18 0
|
14天前
|
存储 SQL 关系型数据库
【MySQL实战笔记】03.事务隔离:为什么你改了我还看不见?-02
【4月更文挑战第7天】数据库通过视图实现事务隔离,不同隔离级别如读未提交、读已提交、可重复读和串行化采用不同策略。以可重复读为例,MySQL使用多版本并发控制(MVCC),每个事务有其独立的视图。回滚日志在无更早视图时被删除。长事务可能导致大量存储占用,应避免。事务启动可显式用`begin`或设置`autocommit=0`,但后者可能意外开启长事务。建议使用`autocommit=1`并显式管理事务,若需减少交互,可使用`commit work and chain`。
30 5
|
27天前
|
关系型数据库 MySQL 测试技术
面试-MySQL的四种事务隔离级别
面试-MySQL的四种事务隔离级别
18 0
|
17天前
|
关系型数据库 MySQL 数据库
mysql卸载、下载、安装(window版本)
mysql卸载、下载、安装(window版本)
|
1月前
|
关系型数据库 MySQL 数据库
rds安装数据库客户端工具
安装阿里云RDS的数据库客户端涉及在本地安装对应类型(如MySQL、PostgreSQL)的客户端工具。对于MySQL,可选择MySQL Command-Line Client或图形化工具如Navicat,安装后输入RDS实例的连接参数进行连接。对于PostgreSQL,可以使用`psql`命令行工具或图形化客户端如PgAdmin。首先从阿里云控制台获取连接信息,然后按照官方文档安装客户端,最后配置客户端连接以确保遵循安全指引。
86 1
|
6天前
|
关系型数据库 MySQL 数据库
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
28 4
|
29天前
|
Ubuntu 关系型数据库 MySQL
Ubuntu 中apt 安装MySQL数据库
Ubuntu 中apt 安装MySQL数据库
69 0