MySQL 事务原理:事务概述、隔离级别、MVCC-2

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: MySQL 事务原理:事务概述、隔离级别、MVCC

2.3.4 丢失更新

脏读、不可重复读、幻读都是一个事务写,一个事务读,由于一个事务的写导致另一个事务读到了不该读的数据。

丢失更新是两个事务都是写。丢失更新分为提交覆盖和回滚覆盖;回滚覆盖会被数据库拒绝,所以不可能产生,重点关注提交覆盖。


seq session A session B
1 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
2 BEGIN; BEGIN;
3 SELECT money FROM account_t WHERE name = ‘A’;
4 SELECT money FROM account_t WHERE name = ‘A’;
5 UPDATE account_t SET money = 1100 WHERE name = ‘A’;
6 COMMIT;
7 UPDATE account_t SET money = 1100 WHERE name = ‘A’;
8 COMMIT;


2.4 区别

1)脏读和不可重复读的区别在于,脏读是读取了另一个事务未提交的数据,而不可重复读是读取了另一个事务提交后的修改。本质上都是其他事务的修改影响了本事务的读取。


2)不可重复读和幻读比较类似;不可重复读是两次读取同一条记录,得到不一样的结果;而幻读是两次读取同一个范围内的记录得到的结果集不一样(可能不同个数,也可能相同个数内容不一样,比如x一行后又添加新行)。


3)不可重复读是因为其他事务进行了 update 操作,幻读是因为其他事务进行了 insert或者 delete 操作。


隔离级别 回滚覆盖 脏读 不可重复读 幻读 提交覆盖
READ UNCOMMITTED NO YES YES YES YES
READ COMMITTED NO NO YES YES YES
REPEATABLE REA NO NO NO YES (手动加锁) YES (手动加锁)
SERIALIZABLE NO NO NO NO NO

MySQL InnoDB 引擎的默认隔离级别是可重复读,但是它可以很大程度上避免幻读现象。

1)针对快照读:通过 MVCC 方式解决了幻读。因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。


2)针对当前读:是通过 next-key lock(记录锁+间隙锁)方式解决了幻读。因为当执行 select 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。


2.5 测试代码

DROP TABLE IF EXISTS `account_t`;
CREATE TABLE `account_t` (
  `id` INT(11) NOT NULL,
  `name` VARCHAR(255) DEFAULT NULL,
  `money` INT(11) DEFAULT 0,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
)ENGINE = INNODB AUTO_INCREMENT=0 DEFAULT CHARSET = utf8;
SELECT * from account_t;
rollback;
INSERT INTO `account_t` VALUES (7,'M',1000), (1, 'C', 1000),(2, 'B', 1000),(3, 'A', 1000);
insert into 
-- 脏读读取了另一个事务未提交的修改 (其他事务的修改影响了本事务的读取)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
-- 脏读事务1
UPDATE account_t SET money = money - 100 WHERE name = 'A';
-- 脏读事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- SELECT money FROM account_t WHERE name = 'B';
-- 脏读事务1
UPDATE account_t SET money = money + 100 WHERE name = 'B';
-- 脏读事务1
COMMIT;
-- 脏读事务2
-- COMMIT
-- 不可重复读读取了另一个事务提交之后的修改(其他事务的修改影响了本事务的读取)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
-- 不可重复读事务2
SELECT money FROM account_t WHERE name = 'A';
-- 不可重复读事务1
UPDATE account_t SET money = money - 100 WHERE name = 'A';
-- 不可重复读事务1
COMMIT;
-- 不可重复读事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- COMMIT
-- 幻读两次读取得到的结果集不一样
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
-- 幻读事务2
-- SELECT * FROM account_t WHERE id >= 2;
-- 幻读事务1
INSERT INTO account_t(id,name,money) VALUES (4,'D',1000);
-- 幻读事务1
COMMIT
-- 幻读事务2
-- SELECT * FROM account_t WHERE id >= 2;
-- COMMIT;
-- 丢失更新(提交覆盖)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
-- 丢失更新事务1
SELECT money FROM account_t WHERE name = 'A';
-- 丢失更新事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- UPDATE account_t SET money = 1100 WHERE name = 'A';
-- COMMIT;
-- 丢失更新事务1
UPDATE account_t SET money = 900 WHERE name = 'A';
COMMIT;


三、MVCC


MVCC 是啥?

一般解决不可重复读和幻读问题,是采用锁机制实现,有没有一种乐观锁的问题去处理,可以采用 MVCC 机制的设计,可以用来解决这个问题。取代行锁,降低系统开销。

MVCC 的英文全称是 Multiversion Concurrency Control ,中文意思是多版本并发控制技术。原理是,通过数据行的多个版本管理来实现数据库的并发控制,简单来说就是保存数据的历史版本。可以通过比较版本号决定数据是否显示出来。读取数据的时候不需要加锁可以保证事务的隔离效果。它是通过数据库记录中的隐式字段,undo 日志 ,Read View 来实现的。


MVCC 可以解决什么问题?

1、读写之间阻塞的问题,通过 MVCC 可以让读写互相不阻塞,读不相互阻塞,写不阻塞读,这样可以提升数据并发处理能力。

2、降低了死锁的概率,这个是因为 MVCC 采用了乐观锁的方式,读取数据时,不需要加锁,写操作,只需要锁定必要的行。

3、解决了一致性读的问题,也就是事务启动时根据某个条件读取到的数据,直到事务结束时,再次执行相同条件,还是读到同一份数据,不会发生变化。


多版本并发控制 MVCC(Multiversion Concurrency Control),用来实现一致性的非锁定读。非锁定读是指不需要等待访问记录 X 锁(排他锁)的释放。因此 MVCC 没有读写阻塞,只有写写阻塞,提高了并发性。


在 read committed 和 repeatable read 下,innodb 使用MVCC;但是它们对于快照数据的定义不同。

1)在 read committed 隔离级别下,对于快照数据总是读取被锁定行的最新一份快照数据;

2)而在 repeatable read 隔离级别下,对于快照数据总是读取事务开始时的行数据版本;


3.1 read view

read view 是事务进行快照读的时候产生的读视图,保存了当前事务开启时所有活跃事务的列表。


在 read committed 和 read repeatable 隔离级别下,MVCC 采用read view 来实现的,它们的区别在于创建 read view 时机不同:

1)read committed 隔离级别会在事务中每个 select 都会生成一个新的 read view,也意味着在同一个事务多次读取同一条数据可能出现数据不一致;因为在多次读取期间可能有其他事务修改了该条记录,并提交了;


2)read repeatable 隔离级别是启动事务时生成一个 readview,在整个事务读取数据都才使用这个 read view,这样保证了在事务期间读到的数据都是事务启动前的记录。


3.1.1 构成

1) m_ids :创建 read view 时,当前数据库活跃事务(已启动但未提交的事务)的事务 id 列表;


2)min_trx_id :创建 read view 时, m_ids 中的最小事务 id;


3)max_trx_id :创建 read view 时,当前数据库将为下一个事务分配的事务 id;并不一定是 m_ids 中的最大事务 id;


4)creator_trx_id :创建 read view 所在事务的 id;


18fcc980765192b48eab959fee56be4e_81996200578f4ac0a64a891cac7ae2d6.png


3.2 当前读 & 快照读

3.2.1 当前读(Current Read)


当前读是指读取最新提交的数据。当进行当前读时,事务会读取已经提交并且已经写入到数据库中的最新数据。当前读可以获取到最新的数据,但也可能会受到并发事务的影响,因为正在执行的事务可能会修改正在被读取的数据,从而导致一致性问题。对此,当前读使用行级锁定来确保读取最新提交的数据的一致性。


-- 出现当前读的情况
-- 1
select * from table where ... lock in share mode;
-- 2
select * from table where ... for update;
-- 3
insert into table values(...);
-- 4
update table set ?=? where ...;
-- 5
delete from table where ...;

3.2.2 快照读(Snapshot Read)

快照读是指读取一个指定时间点的数据快照。当进行快照读时,事务会读取在事务开始之前已提交的数据状态,即使在事务执行期间其他事务进行了更改或提交。这意味着快照读可以提供一种一致性的视图,不受并发事务的干扰。


MVCC 的读指的是快照读(非锁定读),因为没有事务需要对历史数据进行 DML 操作。

在读已提交和可重复读的隔离级别下,对于快照数据的定义不同

RC 级别:读取当前事务锁定行的最新行记录。

RR 级别:读取启动事务时的行记录版本。


-- 出现快照读的情况
select * from table where ......

3.3 聚集索引隐藏列

1)trx_id :当某个事务对某条聚集索引记录进行修改时,将会把当前事务的 id 赋值给 trx_id;


2)roll_pointer :当某个事务对某条聚集索引记录进行修改时,会将上一个版本的记录写到 undo log,然后通过roll_pointer 指向旧版本记录,通过它可以找到修改前的记录;


3.4 事务的可见性问题

3.4.1 事务状态


1)已提交的事务


2)已启动未提交的事务


3)还没开始的事务


3.4.2 事物的可见性


事务可以看到事物本身的修改。具体可以通过如下判断:


1)trx_id < min_trx_id :说明该记录在创建 read_view 之前已经提交,所以对当前事务可见;


2)trx_id >= max_trx_id :说明该记录是在创建 read_view 之后启动事务生成的,所以对当前事务不可见;


3)min_trx_id <= trx_id < max_trx_id :此时需要判断是否在 m_ids 列表中:

在列表中:生成该版本记录的事务仍处于活跃状态,该版本记录对当前事务不可见;

不在列表中:生成该版本记录的事务已经提交,该版本记录对当前事务可见;


e14915bb3544f8a6d955abcaaccb8567_7c3c4941044f4510bf936e87888d562d.png


四、redo log


redo 日志用来实现事务的持久性;

内存中包含 redo logbuffer,磁盘中包含 redo log file;


当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务的 commit 操作完成才完成了事务的提交;


redo log 顺序写,记录的是对每个页的修改(页、页偏移量、以及修改的内容);在数据库运行时不需要对 redo log 的文件进行读取操作;只有发生宕机的时候,才会拿redo log 进行恢复。


五、undo log


undo 日志用来帮助事务回滚以及 MVCC 的功能;存储在共享表空间中;


undo 是逻辑日志,回滚时将数据库逻辑地恢复到原来的样子,根据 undo log 的记录,做之前的逆运算;比如事务中有 insert 操作,那么执行 delete 操作;对于 update 操作执行相反的 update 操作;


同时 undo 日志记录行的版本信息,用于处理 MVCC 功能

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 SQL 关系型数据库
MySQL进阶突击系列(03) MySQL架构原理solo九魂17环连问 | 给大厂面试官的一封信
本文介绍了MySQL架构原理、存储引擎和索引的相关知识点,涵盖查询和更新SQL的执行过程、MySQL各组件的作用、存储引擎的类型及特性、索引的建立和使用原则,以及二叉树、平衡二叉树和B树的区别。通过这些内容,帮助读者深入了解MySQL的工作机制,提高数据库管理和优化能力。
|
1月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
MySQL事务日志-Undo Log工作原理分析
|
27天前
|
SQL 关系型数据库 MySQL
MySQL派生表合并优化的原理和实现
通过本文的详细介绍,希望能帮助您理解和实现MySQL中派生表合并优化,提高数据库查询性能。
68 16
|
2月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
2月前
|
关系型数据库 MySQL 数据库
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
在这一章节,主要介绍两个部分,数据库相关概念及MySQL数据库的介绍、下载、安装、启动及连接。接着,详细描述了MySQL 8.0的版本选择与下载,推荐使用社区版(免费)。安装过程包括自定义安装路径、配置环境变量、启动和停止服务、以及客户端连接测试。此外,还提供了在同一台电脑上安装多个MySQL版本的方法及卸载步骤。最后,解释了关系型数据库(RDBMS)的特点,即基于二维表存储数据,使用SQL语言进行操作,格式统一且便于维护。通过具体的结构图展示了MySQL的数据模型,说明了数据库服务器、数据库、表和记录之间的层次关系。
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
|
28天前
|
SQL 关系型数据库 MySQL
MySQL派生表合并优化的原理和实现
通过本文的详细介绍,希望能帮助您理解和实现MySQL中派生表合并优化,提高数据库查询性能。
36 7
|
26天前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合
2024年小结:感谢阿里云开发者社区每月的分享交流活动,支持持续学习和进步。过去五个月投稿29篇,其中17篇获高分认可。本文详细介绍了MySQL InnoDB存储引擎的MVCC机制,包括数据版本链、readView视图及解决脏读、不可重复读、幻读问题的demo演示。
|
2月前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
2月前
|
缓存 关系型数据库 MySQL
MySQL 索引优化与慢查询优化:原理与实践
通过本文的介绍,希望您能够深入理解MySQL索引优化与慢查询优化的原理和实践方法,并在实际项目中灵活运用这些技术,提升数据库的整体性能。
119 5
|
2月前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。