一文带你理解MySQL事务核心知识点

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 一文带你理解MySQL事务核心知识点

前言


关于事务,可能大家和我一样知道一些基本的概念,包括4大特性等,但是对于他们理解的可能不够深入,包括MySQL是用什么样的机制去实现这样的特性,都可能很懵逼,那么本文就和大家一起来排坑,从事务的基础知识点到基本的实现,我们都需要做到心中有数。

1671199912877.jpg


事务的概念


事务(Transaction)是一组逻辑操作单元,使数据从一种状态变换到另一种状态。这里的逻辑操作单元是根据我们的业务场景来定的,比如银行转账的场景,A用户转账给B用户500元,会出现下面两条SQL,我们把这样一组SQL形成的数据操作看作一个事务。

# A用户转账给B用户500元
update account set money = money - 500 where name = 'A';
# 服务器宕机等等,或者业务层代码报错
update account set money = money + 500 where name = 'B';

一个事务中的SQL要么都执行,要么都不执行。比如上面的例子中,A用户账户扣了500元后,突然宕机了,第2个SQL未执行,那么导致了A用户平白无故不见了500元,这样影响的后果是非常灾难的。

MySQL中只有InnoDB存储引擎支持事务,其他引擎不支持,这也是为什么大家都是用的InnoDB存储引擎,因为事务的保障真的非常非常重要,它是保证业务正常、稳定运行的基础。

1671199925878.jpg


事务的使用


使用事务有两种方式,分别为 显式事务隐式事务


显式事务


  1. ****START TRANSACTION 或者 BEGIN ,作用是显式开启一个事务。
mysql> BEGIN; 
#或者 
mysql> START TRANSACTION;

START TRANSACTION 语句相较于 BEGIN 特别之处在于,后边能跟随几个 修饰符

  • READ ONLY :标识当前事务是一个 只读事务 ,也就是属于该事务的数据库操作只能读取数据,而不能修改数据, 如START TRANSACTION READ ONLY;
  • READ WRITE :标识当前事务是一个 读写事务 ,也就是属于该事务的数据库操作既可以读取数据, 也可以修改数据, 默认为该模式,如START TRANSACTION READ WRITE
  • WITH CONSISTENT SNAPSHOT :立即启动一致性读视图, START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT
  1. 一系列事务中的操作
  2. 提交事务
# 开启事务
mysql> BEGIN;
# 数据库操作
mysql> .......;
# 提交事务。当提交事务后,对数据库的修改是永久性的。 
mysql> COMMIT;
  1. 回滚事务rollback
# 开启事务
mysql> BEGIN;
# 数据库操作
mysql> .......;
# 回滚事务。即撤销正在进行的所有没有提交的修改 
mysql> ROLLBACK; 
  1. 回滚事务到保存点SAVEPOINT
# 开启事务
mysql> BEGIN;
# 数据库操作
mysql> .......;
# 设置保存点 SAVEPOINT name
mysql> SAVEPOINT s1; 
# 数据库操作
mysql> .......; 
# 将事务回滚到某个保存点 ROLLBACK TO [SAVEPOINT]
mysql> ROLLBACK TO s1

其中关于SAVEPOINT相关操作有:

  • 在事务中创建保存点,方便后续针对保存点进行回滚。一个事务中可以存在多个保存点。 SAVEPOINT 保存点名称;
  • 删除某个保存点 RELEASE SAVEPOINT 保存点名称;


隐式事务


  1. autocommit引起隐式事务

MySQL中有一个系统变量 autocommit

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    |  ON   |
+---------------+-------+
1 row in set (0.01 sec)

当然,如果我们想关闭这种 自动提交 的功能,可以使用下边两种方法之一:

  • 显式的的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务。这样在本次事务提交或者回滚前会暂时关闭掉自动提交的功能。
  • 把系统变量 autocommit 的值设置为 OFF,就像这样:
SET autocommit = OFF; 
#或 
SET autocommit = 0;
  1. 特殊语句导致事务隐式提交

在MySQL中,存在一些特殊的命令,如果在事务中执行了这些命令,会马上强制执行commit提交事务;如DDL语句(create table/drop table/alter/table)、lock tables语句等等。即:

BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其他语句
CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务


理解事务的ACID四大特性


为了保证业务的安全、平稳运行,比如数据不一致或者数据丢失等情况,这就需要我们的事务满足一定的特性,即原子性(atomicity),一致性(consistency),隔离型(isolation)和持久性(durability)4大特性。

实际上,在各大数据库厂商的实现中,真正满足ACID的事务少之又少。例如MySQL的NDB Cluster事务不满足持久性和隔离性;InnoDB默认事务隔离级别是可重复读,不完全满足隔离性;Oracle默认的事务隔离级别为读已提交,也不完全满足隔离性……因此与其说ACID是事务必须满足的条件,不如说它们是衡量事务的四个维度。


原子性(Atomicity)


说明:

原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。比如A账户减去500元,而B账户增加500元时操作失败,这时候系统应该进行回滚,退回到事务开始前,也就是A账户减去500元前的状态。

实现机制:

那如何实现事务的原子性,即事务可以回滚呢?

是不是可以在事务中执行SQL的时候,在日志文件中记录下对应数据修改前的值,当事务执行update时,其生成的日中包含被修改行的主键、修改了哪些列、这些列在修改前后的值等信息,回滚时便可以使用这些信息将数据还原到update之前的状态。

上面提到的这个日志文件就是undo log,undo log属于逻辑日志,它记录的是sql执行相关的信息。当发生回滚时,InnoDB会根据undo log的内容做与之前相反的工作:对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update,把数据改回去。


一致性(Consistency)


说明:

一致性是指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态 。这里的合法性状态是满足一定的约束,是根据具体的业务决定的。比如:A账户有100元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时的数据是不一致的,为什么呢?因为你定义了一合法性个状态,要求A+B的总余额必须不变。

实现原理:

MySQL innoDB引擎中数据的一致性和原子性一样,也是用事务日志undo log实现的。****


持久性(Durability)


说明:

指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

实现原理:

事务的持久性是通过另外一个事务日志redo log实现的。

1671199976395.jpg

  • 当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到redo log中
  • 然后再对数据库中对应的行进行修改
  • 即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。


隔离性(Isolation)


事务的隔离性是4大特性中最复杂的一种,它主要关注的是不同事务之间的相互影响,特别是在不同事务并发执行的情况。

如果完全不做隔离性的话,并发事务会引发下面的一系列问题。

事务并发问题

  1. 脏读

脏读是指的一个事务读取到了另外一个事务未提交的数据。


1671199985267.jpg


  • Session B中的事务先将studentno列为1的记录的name列更新 为'张三',
  • 然后Session A中的事务再去查询这条studentno为1的记录,读到未提交的值'张三'
  • Session B中的事务稍后进行了回滚
  • 这时Session A中的事务相当于读到了一个不存在的数据,这种现象就称之为 脏读
  1. 不可重复读

不可重复读是指一个事务中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。


1671199994149.jpg


  1. 幻读( Phantom )

幻读是指一个事务中按照某个条件先后两次查询数据库,两次查询结果的条数不同,更加强调的是读到了之前没有读到的数据,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。


1671200002661.jpg


事务隔离级别

事务之间严格的隔离肯定是不同的事务之间可以完全互不干扰,比如A事务"干活"的时候,B事务先等等,等A干完了再干,这样肯定不会有上面一系列并发问题,但是这会导致性能十分糟糕。

因此,我们引入了隔离级别,SQL 标准定义了4种事务隔离级别,包括读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable)。隔离级别越高,性能也就越差。

  1. 读未提交(read uncommitted)

读未提交指一个事务还没提交时,它做的变更就能被别的事务看到。该隔离级别下不能避免脏读、不可重复读、幻读。

1671200017105.jpg

  • 事务1开启了read uncommitted的隔离级别
  • 事务2读取到了事务1未提交的数据
  1. 读提交(read committed)

读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。该隔离级别下可以避免脏读,但不可重复读、幻读问题仍然存在。

1671200023091.jpg

  • 事务开启了read committed的隔离级别
  • 事务1前后两次读取到的值不一样,发生了不可重复读问题
  1. 可重复读(repeatable read)

可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提 交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍 然存在。这是MySQL的默认隔离级别。

1671200029377.jpg

  • 事务开启了repeatable read的隔离级别
  • 事务1一开始明明没有id=3的数据,但是无法插入,发生了幻读现象
  1. 序列化(serializable)

顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。该隔离级别下,所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。

小结:

不同的隔离级别能解决的并发问题,如下图所示:

1671200035329.jpg

隔离级别越高,性能也会越差,这就需要我们去做取舍。

1671200042529.jpg

实现机制

隔离性的实现机制相对来说还是比较复杂的,根据事务的读写场景不一致,我们大致可以分为两类:

  1. (一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性

隔离性要求同一时刻只能有一个事务对数据进行写操作,InnoDB通过锁机制来保证这一点。事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据。该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。

  • (一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性

MVCC全称Multi-Version Concurrency Control,即多版本的并发控制协议。在同一时刻,不同的事务读取到的数据可能是不同的(即多版本)。每个事务会有一个自己的ReadView, 所谓ReadView,是指事务在某一时刻给整个事务系统打快照,之后再进行读操作时,会将读取到的数据中的事务id与trx_sys快照比较,从而判断数据对该ReadView是否可见。

具体关于MVCC机制将在后面的文章深入剖析。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
105 43
|
27天前
|
存储 Oracle 关系型数据库
[MySQL]知识点
本文详细介绍了MySQL中int族和char族数据类型的特点、存储范围及使用建议,以及text、blob类型和内置字符处理函数。文章强调了数据类型选择的重要性,并提供了多个实例帮助理解。
33 0
[MySQL]知识点
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1654 14
|
3月前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
572 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
2月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
3月前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
152 4
MySQL基础:事务
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL】索引和事务
【MySQL】索引和事务
55 0
|
3月前
|
SQL Oracle 关系型数据库
详解 MySQL 的事务以及隔离级别
详解 MySQL 的事务以及隔离级别
44 0
|
4月前
|
SQL 关系型数据库 MySQL
Mysql原理与调优-事务与MVCC
【8月更文挑战第19天】
|
4月前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制