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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 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 功能

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3天前
|
SQL 关系型数据库 MySQL
mysql主从复制概述和配置
【10月更文挑战第22天】MySQL 主从复制是一种将主服务器的数据复制到一个或多个从服务器的技术,实现读写分离,提高系统性能和可用性。主服务器记录变更日志,从服务器通过 I/O 和 SQL 线程读取并应用这些变更。适用于读写分离、数据备份和恢复、数据分析等场景。配置步骤包括修改配置文件、创建复制用户、配置从服务器连接主服务器并启动复制进程。
|
14天前
|
缓存 算法 关系型数据库
Mysql(3)—数据库相关概念及工作原理
数据库是一个以某种有组织的方式存储的数据集合。它通常包括一个或多个不同的主题领域或用途的数据表。
38 5
Mysql(3)—数据库相关概念及工作原理
|
13天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1576 12
|
5天前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
8天前
|
存储 关系型数据库 MySQL
RR隔离级别在MySQL中的实现与幻读问题探讨
【10月更文挑战第3天】在数据库管理系统中,事务隔离级别是确保数据一致性和并发性能的关键要素。MySQL作为广泛使用的关系型数据库管理系统,支持多种事务隔离级别,其中可重复读(Repeatable Read,简称RR)是其默认隔离级别。本文将深入探讨RR隔离级别在MySQL中的实现原理,以及RR隔离级别下幻读问题的产生与解决方案。
30 2
|
16天前
|
存储 SQL 关系型数据库
mysql中主键索引和联合索引的原理与区别
本文详细介绍了MySQL中的主键索引和联合索引原理及其区别。主键索引按主键值排序,叶节点仅存储数据区,而索引页则存储索引和指向数据域的指针。联合索引由多个字段组成,遵循最左前缀原则,可提高查询效率。文章还探讨了索引扫描原理、索引失效情况及设计原则,并对比了InnoDB与MyISAM存储引擎中聚簇索引和非聚簇索引的特点。对于优化MySQL性能具有参考价值。
|
27天前
|
关系型数据库 MySQL 数据库
深入理解MySQL数据库隔离级别
深入理解MySQL数据库隔离级别
84 1
|
17天前
|
SQL 关系型数据库 MySQL
【MySQL】索引和事务
【MySQL】索引和事务
36 0
|
27天前
|
SQL Oracle 关系型数据库
详解 MySQL 的事务以及隔离级别
详解 MySQL 的事务以及隔离级别
26 0
|
9天前
|
存储 SQL 关系型数据库
Mysql学习笔记(二):数据库命令行代码总结
这篇文章是关于MySQL数据库命令行操作的总结,包括登录、退出、查看时间与版本、数据库和数据表的基本操作(如创建、删除、查看)、数据的增删改查等。它还涉及了如何通过SQL语句进行条件查询、模糊查询、范围查询和限制查询,以及如何进行表结构的修改。这些内容对于初学者来说非常实用,是学习MySQL数据库管理的基础。
44 6