高性能 MySQL(三):事务与锁详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 事务(Transaction)是一个独立的工作单元,它由一组具有原子性的 SQL 语句构成,通常该组 SQL 语句对应着一个完整的业务。在事务内的语句,要么全部执行成功,要么全部执行失败。

大家好,我是水滴~~

事务(Transaction)是一个独立的工作单元,它由一组具有原子性的 SQL 语句构成,通常该组 SQL 语句对应着一个完整的业务。在事务内的语句,要么全部执行成功,要么全部执行失败。

1 一个转账例子

我们使用一个典型的“转账”例子来解释事务。下表为用户表user,每个用户都有自己的余额balance(该表的存储引擎为 InnoDB)。

139cabc7510b6d1e76f1490220e1da80_image_auth_key=1686635155-jWDYRoc3WZg9CEbMbnBZj2-0-9005611fe5a8ed823b0e46ded40ed6b1&file_size=13358.png

现在要从“刘一”账号中转账20元给“陈二”,那么至少需要两个步骤:

  1. 从“刘一”账户余额中减去20元;
  2. 在“陈二”账户余额中增加20元。

上述两个步骤作,在不使用事务的情况下,如果第二步没有执行成功,那么“刘一”余额已经减去了20元,而“陈二”的余额没有变化,会造成数据不一致。所以这两个步骤必须放在一个事务中,它们就是一个独立的工作单元,任何一个步骤失败,则必须回滚所有步骤。

事务中,有三种操作:

  1. beginstart transaction:开始一个事务;
  2. rollback:回滚事务,会撤销所有修改;
  3. commit:提交事务,将修改的数据持久化到数据库文件。

那么这个转账事务的 SQL 语句如下:

begin;
update `user` set blance = blance - 20 where id = 1;
update `user` set blance = blance + 20 where id = 2;
commit;

❤️ 在事务提交之前,存储引擎在修改表数据时,并不是直接修改磁盘中的数据库文件,而是先在内存中修改。事务提交后,才会将内存中修改的数据刷回磁盘中。这块内容在后面的“事务日志”章节再详聊。

2 事务的四大特性(ACID)

一个运行良好的事务处理系统,必须要具备 ACID 标准特性。

2.1 原子性(Atomicity)

一个事务必须是一个不可分割的最小工作单元,整个事务中所有操作要么全部成功提交,要么全部失败回滚。

2.2 一致性(Consistency)

一致性描述了数据库中数据的状态,数据总是从一个一致的状态转换为另一个一致的状态。

在上例中,一致性确保了:转账成功,“刘一”的钱减少了20元,“陈二”的钱增加了20元;转账失败,“刘一”和“陈二”的钱都没有变化,因为事务中所有操作全部回滚,并没有保存到数据库中。

2.3 隔离性(Isolation)

在多个事务并发执行时,一个事务所做的修改在提交以前,对其他事务“通常来说”是不可见的,它们是相互隔离的。

之所以是“通常来说”是不可见的,是因为事务具有隔离级别(Isolation Level)。隔离级别不同,可见性也不同,后面章节会有介绍。

2.4 持久性(Durability)

一旦事务提交后,其所做的修改就会永久保存到数据库中。

❤️ 事务的 ACID 特性可以确保转账时不会弄丢你的钱,为了确保事务处理过程中是安全的,也需要数据库系统做更多的额外工作。一个实现了 ACID 的存储引擎,通常会需要更强的 CPU 处理能力、更大的内存和更多的磁盘空间。这也正是 MySQL 存储引擎架构的强大之处,用户可以根据业务是否需要事务处理,来选择合适的存储引擎 。对于一些不需要事务操作的应用,选择一个非事务型存储引擎,可以获得更高的性能。

3 隔离级别

在 SQL 标准中定义了四种隔离级别,每一种隔离级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。

3.1 未提交读(Read Uncommitted)

在未提交读级别中,事务中的修改,即使没有提交,对其他事务也是可见的。

事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。这个级别会导致很多问题,在实际应用中一般很少使用。

3.2 提交读(Read Committed)

一个事务在提交之前所做的任何修改,对其他事务是不可见的,只有提交后才能被其他事务“看到”。

这个级别也被叫做不可重复读(Nonrepeatable Read),因为两次执行同样的查询,结果可能不一样。

该级别是大多数数据库系统的默认隔离级别(MySQL 不是)。

3.3 可重复读(Repeatable Read)

该级别保证了在同一个事务中,多次读取同样记录的结果是一致的。

理论上,可重复读还是无法解决另一个幻读(Phantom Read)的问题。所谓幻读,指的是当 A 事务在读取某个范围内的记录时,B 事务往该范围内插入了新的记录,那么 A 事务再次读取该范围时,就会产生幻行(Phantom Row)。而InnoDB 和 XtraDB 存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。

该级别是 MySQL 的默认隔离级别。

3.4 可串行化(Serializable)

可串行化是最高的隔离级别,它通过强制事务串行执行,避免了前面说的幻读问题。

该级别通过在读取的每一行记录上加锁,实现的串行执行,所以可能会导致大量的超时和锁竞争问题,在实际应用中也很少使用。

ANSI SQL 隔离级别:

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
未提交读 Yes Yes Yes No
提交读 No Yes Yes No
可重复读 No No Yes No
可串行化 No No No Yes

4 死锁

死锁是指两个或多个事务,在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

例如,下面两个事务同时处理user表:

事务 A

begin;
update `user` set balance = 10 where id = 3;
update `user` set balance = 20 where id = 4;
commit;

事务 B

begin;
update `user` set balance = 30 where id = 4;
update `user` set balance = 40 where id = 3;
commit;

如果两个事务都执行了第一条update语句,更新了一行数据,同时也锁定了该行数据,接着每个事务都尝试去执行第二条update语句,却发现该行已经被对方锁定,然后两个事务都等待对方释放锁,同时又待有对方需要的锁,就会陷入一种死循环。

下面使用刚才的事务 A事务 B 来演示下死锁:

19885624620e288f83b955a060024bab_%E6%AD%BB%E9%94%81_auth_key=1686635174-RB1aYchrbxKhpgbo2BFQB-0-8b91b8036cdcd2d043e7e22d04d37f96&file_size=324966.gif

数据库系统是有死锁检测和处理机制的,我们看到上例中的 InnoDB 存储引擎,能够检测到死锁的循环依赖,并立即返回一个错误。

❤️ InnoDB处理死锁的方法是,将持有最少行级排他锁的事务进行回滚,其他事务就可以获到锁了。

5 事务日志

在修改表的数据时,实际修改的是其内存的拷贝,存储引擎会将修改的行为记录到磁盘上的事务日志中。事务日志持久以后,内存中被修改的数据会被存储引擎慢慢地刷回磁盘数据库文件中。也就是说,修改数据需要写两次磁盘。

如果数据的修改已经持久化到事务日志中,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。具体的恢复方式视存储引擎而定。

6 MySQL 中的事务

MySQL提供了两种事务型存储引擎:InnoDB 和 NDB Cluster。另外还有一些第三方存储引擎也支持事务,比如:XtraDB 和 PBXT。

6.1 自动提交

MySQL 默认使用的是自动提交(Autocommit)模式。也就是说,MySQL 中的每个 SQL 操作都被当作一个事务执行提交操作。当然你也可以禁用自动提交模式,改为手动提交,但这种方式不推荐。

对于非事务型存储引擎,如 MyISAM,不会受事务影响,这类表没有commitrollback的概念,你可以理解它是一直处于自动提交模式。

6.2 事务中不可混用存储引擎

事务是由存储引擎来实现,不能在一个事务中混合使用事务型和非事务型的表(例如 InnoDB 和 MyISAM 表)。

如果混合使用,而事务需要回滚时,非事务型的表上的修改就无法撤销了,违反了事务的一致性。

7 隐式和显式锁定

InnoDB 采用的是两阶段锁定协议(Two-phase Locking Protocol)。在事务执行过程中,如果执行到 DML 语句时,会自动将范围内的记录锁定。锁只有在执行commit或者rollback的时候才会释放,并且是事务内所有锁在同一时刻被翻译。这种方式的锁定就是隐式锁定

DML(Data Manipulation Language,数据操作语言)主要有三种方式:插入(INSERT)、修改(UPDATE)和删除(DELETE)。

显式锁定通过一些特定的语句来实现,在上一篇《高性能 MySQL(二):并发控制(锁)》中已经介绍过:

select ... lock in share mode;
select ... for update;

e4d7990c77833831aa35d59ba8475095_%E4%B8%89%E8%BF%9E_auth_key=1686634967-5NapvvxdcDPTbbVmBVUzjR-0-9659e7ae6fdb7e379e4a12398264e890&file_size=1423542.gif

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
21天前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
5天前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
19 5
|
28天前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
88 4
MySQL基础:事务
|
5天前
|
存储 SQL 关系型数据库
MySQL 的锁机制,那么多的锁,该怎么区分?
MySQL 的锁机制,那么多的锁,该怎么区分?
15 0
|
5天前
|
SQL Oracle 关系型数据库
详解 MySQL 的事务以及隔离级别
详解 MySQL 的事务以及隔离级别
11 0
|
27天前
|
关系型数据库 MySQL 数据库
Mysql的锁
本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
|
2月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
68 0
|
2月前
|
C# Windows 监控
WPF应用跨界成长秘籍:深度揭秘如何与Windows服务完美交互,扩展功能无界限!
【8月更文挑战第31天】WPF(Windows Presentation Foundation)是 .NET 框架下的图形界面技术,具有丰富的界面设计和灵活的客户端功能。在某些场景下,WPF 应用需与 Windows 服务交互以实现后台任务处理、系统监控等功能。本文探讨了两者交互的方法,并通过示例代码展示了如何扩展 WPF 应用的功能。首先介绍了 Windows 服务的基础知识,然后阐述了创建 Windows 服务、设计通信接口及 WPF 客户端调用服务的具体步骤。通过合理的交互设计,WPF 应用可获得更强的后台处理能力和系统级操作权限,提升应用的整体性能。
69 0
|
2月前
|
存储 关系型数据库 MySQL
MySQL 中的事务存储引擎深入解析
【8月更文挑战第31天】
28 0
|
2月前
|
关系型数据库 MySQL 数据库
MySQL MVCC和间隙锁有什么区别?
【8月更文挑战第24天】MySQL MVCC和间隙锁有什么区别?
44 0
下一篇
无影云桌面