【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 本文以热门游戏《黑神话:悟空》为契机,深入浅出地解析了数据库事务的四种隔离级别:读未提交、读已提交、可重复读和串行化。通过具体示例,展示了不同隔离级别下的事务行为差异及可能遇到的问题,如脏读、不可重复读和幻读等。此外,还介绍了在MySQL中设置隔离级别的方法,包括全局和会话级别的调整,并通过实操演示了各隔离级别下的具体效果。本文旨在帮助开发者更好地理解和运用事务隔离级别,以提升数据库应用的一致性和性能。

前言

🍊缘由

黑神话悟空玩家必备,数据库隔离级别完全解读

🐣闪亮主角

大家好,我是JavaDog程序狗

今天借着黑神话悟空的热度,跟大家分享一下数据库隔离级别,也是面试必备的八股文

😈你想听的故事

最近狗哥这当面试官的频率越来越多,面试者的水平也参差不齐...

关于数据库隔离级别的问题也是五花八门,有的小伙伴说这完全是八股文,没有实际作用

但狗哥作为搬砖编码小王子,认为基础内容必须掌握,不只为了应付面试,而是提升自己的必经道路

遂狗哥总结数据库隔离级别全攻略,与小伙伴一起分享这个知识点

正文

🎯主要目标

1.MySQL事务隔离级别

2.如何设置隔离级别

3.实操分析隔离级别

🍪目标讲解

一.MySQL四大隔离级别

事务隔离级别
1.读未提交 (Read Uncommitted)
  • 允许一个事务读取另一个事务未提交的数据。
2.读已提交 (Read Committed)
  • 一个事务只能读取另一个事务已经提交的数据。
3.可重复读 (Repeatable Read)
  • 保证在一个事务内多次读取同一数据时,其结果是一致的。
  • 这是 MySQL 默认的隔离级别。
4.串行化 (Serializable)
  • 强制事务串行执行,避免所有并发问题。

隔离水平
1.读未提交 (Read Uncommitted)
  • 隔离水平:最低
  • 特性:允许一个事务读取另一个事务未提交的数据。
2.读已提交 (Read Committed)
  • 隔离水平:较低
  • 特性:一个事务只能读取另一个事务已经提交的数据。
3.可重复读 (Repeatable Read)
  • 隔离水平:较高
  • 特性:保证在一个事务内多次读取同一数据时,其结果是一致的。
  • 默认设置:这是 MySQL 默认的隔离级别。
4.串行化 (Serializable)
  • 隔离水平:最高
  • 特性:强制事务串行执行,避免所有并发问题。

产生问题
1. 读未提交 (Read Uncommitted)
  • 脏读:一个事务读取了另一个事务未提交的数据,如果之后该事务被回滚,则会导致读取的数据无效。
  • 幻读:一个事务读取了一组数据后,另一个事务插入了一些新的数据项,当第一个事务再次读取相同的数据集时,会发现多了未曾见过的行。
  • 不可重复读:一个事务读取了一条数据后,另一个事务修改了这条数据,当第一个事务再次读取时,得到的数据不同。
2. 读已提交 (Read Committed)
  • 不可重复读:一个事务读取了一条数据后,另一个事务修改并提交了这条数据,当第一个事务再次读取时,得到的数据不同。
  • 幻读:一个事务读取了一组数据后,另一个事务插入了一些新的数据项并提交,当第一个事务再次读取相同的数据集时,会发现多了未曾见过的行。
3. 可重复读 (Repeatable Read)
  • 幻读:一个事务读取了一组数据后,另一个事务插入了一些新的数据项并提交,当第一个事务再次读取相同的数据集时,会发现多了未曾见过的行。
    默认设置:这是 MySQL 默认的隔离级别。
4. 串行化 (Serializable)
  • 性能影响:由于所有事务必须串行执行,可能会导致性能下降。
隔离级别 脏读 幻读 不可重复度
读未提交
读已提交 不会
可重复读 不会 不会
串行化 不会 不会 不会

🎯名词解释

  • 脏读

定义:一个事务能够读取到另一个事务尚未提交的数据。

🌰现实例子:想象一下你在银行排队等待办理业务,而你的朋友正在柜台办理转账。你的朋友还没有完成转账操作,也就是说这笔钱还没有真正从他的账户转到你的账户。但是,你却提前看到了自己的账户余额增加了这笔钱。如果这时你的朋友决定取消转账,那么你看到的余额增加就是“脏”的,因为你实际上并没有收到这笔钱。

  • 幻读

定义:幻读是指在一个事务内多次执行相同的查询语句,第二次或以后的查询返回了第一次查询时不存在的额外记录。

🌰现实例子:想象你在一个图书馆查找书籍,第一次查询时找到了10本书关于编程的书。你离开图书馆去喝了杯咖啡,回来后再次查询,发现现在有12本关于编程的书,因为在这段时间里有人捐赠了两本新书。这就像是在同一个事务中两次查询相同条件下的图书数量,但得到的数量不同。

  • 不可重复读

定义:不可重复读是指在一个事务内多次执行相同的查询语句,第二次或以后的查询返回的结果与第一次查询的结果不同。

🌰现实例子:假设你在网上购物,第一次查看某商品的价格是100元。然后你去干别的事情,比如接了个电话。当你再次查看同一件商品的价格时,发现它变成了90元,因为在这段时间里商家做了促销活动降低了价格。这就像是在一个事务中两次查询同一商品的价格,但得到了不同的结果。


二.MySQL设置隔离级别

1.全局设置:
  • 修改 MySQL 的配置文件 (my.cnf 或 my.ini) 中的 innodb_locks_unsafe_for_binlog 和 transaction_isolation 参数
  • 这种设置适用于所有连接到 MySQL 的会话,并且需要重启 MySQL 服务才能生效。
2.会话级别设置:
  • 使用SET SESSION 或 SET 命令来设置当前会话的隔离级别
  • 这种设置只对当前会话有效,并且不会影响其他会话。

具体的 SQL 命令如下:

  • 设置全局隔离级别:
  -- 修改配置文件中的设置
  # 在 my.cnf 或 my.ini 文件中添加如下设置
  [mysqld]
  transaction_isolation = <isolation_level>
  • 设置当前会话隔离级别:
  -- 设置当前会话的隔离级别为 REPEATABLE READ
  SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

  -- 或者简写形式
  SET SESSION tx_isolation='REPEATABLE-READ';
  • 设置当前事务的隔离级别:
  -- 在事务开始之前设置隔离级别
  SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

其中 是你想要设置的隔离级别,可以是以下之一:

READ UNCOMMITTED:最低的隔离级别,允许脏读。

READ COMMITTED:允许不可重复读。

REPEATABLE READ:MySQL 默认的隔离级别,防止不可重复读。

SERIALIZABLE:最高的隔离级别,完全防止脏读、不可重复读和幻读。

🌰示例

假设你想要设置当前会话的隔离级别为 READ COMMITTED,你可以这样操作:

-- 查看当前会话的隔离级别
SELECT @@SESSION.transaction_isolation;

-- 设置当前会话的隔离级别为 READ COMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 再次查看确认是否设置成功
SELECT @@SESSION.transaction_isolation;

💥注意:这些设置只会影响当前会话或当前事务,并且在事务结束后,隔离级别会恢复到之前的设置。如果你希望永久地更改隔离级别,你需要修改配置文件并重启 MySQL 服务。


三.实操分析隔离级别

🍓前置准备:

新建一个产品表,包含主键(id),价格(price),并插入一条数据,用作实际测试

-- 创建表
CREATE TABLE `demo`.`Untitled`  (
  `id` bigint(20) NOT NULL COMMENT '主键id',
  `price` decimal(10, 2) NULL COMMENT '价格',
  PRIMARY KEY (`id`)
);
-- 测试数据
INSERT INTO `demo`.`product` (`id`, `price`) VALUES (1, 10.00);
INSERT INTO `demo`.`product` (`id`, `price`) VALUES (2, 10.00);
INSERT INTO `demo`.`product` (`id`, `price`) VALUES (3, 10.00);
INSERT INTO `demo`.`product` (`id`, `price`) VALUES (4, 10.00);
1.读未提交 (Read Uncommitted)
  • 回顾下读未提交概念

允许一个事务读取另一个事务尚未提交的数据。这种隔离级别提供了最高的并发性,但也可能导致一些问题,如脏读(Dirty Read)和不可重复读(Non-repeatable Read)

  • 读未提交事务1操作

事务1设置事务隔离级别为读未提交,开启事务,修改产品表id=1的price为99,注意这里并未提交事务

-- 设置事务隔离级别为读未提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 开始事务
START TRANSACTION;
-- 更新表中id=1的产品价格
UPDATE product SET price=99 WHERE id=1;
-- 确认更新成功,读未提交事务1查询
SELECT * FROM product WHERE id=1;

  • 读未提交事务2操作

事务2设置事务隔离级别为读未提交,去查看产品表id=1的price,结果是99,也就是读到了事务1中还未提交事务的值

-- 设置事务隔离级别为读未提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 开始事务
START TRANSACTION;
-- 读未提交事务2查询
SELECT * FROM product WHERE id=1;

2. 读已提交 (Read Committed)
  • 回顾下读已提交概念

读已提交它确保每个事务只能看到已经提交的更改,从而避免了脏读,但可能会发生不可重复读和幻读

  • 读已提交事务1操作

事务1设置事务隔离级别为读已提交,开启事务,修改产品表id=2的price为99,注意这里并未提交事务

-- 设置事务隔离级别为读已提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
-- 更新表中id=2的数据
UPDATE product SET price=99 WHERE id=2;
-- 确认上面的UPDATE语句执行成功
SELECT * FROM product WHERE id=2;

  • 读已提交事务2操作

事务2设置事务隔离级别为读已提交,**去查看产品表id=2的price,结果是10,也就事务1更新前的值

-- 设置事务隔离级别为读已提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 开始事务
START TRANSACTION;
-- 读未提交事务2查询
SELECT * FROM product WHERE id=2;

  • 读已提交事务1再操作

将刚才上一步price更新为99的事务进行提交commit

-- 提交事务
COMMIT;

  • 读已提交事务2再操作

事务1已提交,**去查看产品表id=2的price,结果是99,也就事务1更新后的值

-- 读未提交事务2查询
SELECT * FROM product WHERE id=2;

3. 可重复读 (Repeatable Read)
  • 回顾下可重复读概念

可重复读确保在同一个事务内多次读取相同的数据时结果是一致的,即使在这期间有其他事务进行了更新。

  • 可重复读事务1操作

事务1设置事务隔离级别为可重复读,开启事务,修改产品表id=3的price为99,注意这里并未提交事务

-- 设置事务隔离级别为可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
-- 更新表中id=3的数据
UPDATE product SET price=99 WHERE id=3;
-- 确认上面的UPDATE语句执行成功
SELECT * FROM product WHERE id=3;

  • 可重复读事务2操作

事务2设置事务隔离级别为可重复读,**去查看产品表id=2的price,结果是10,也就事务1更新前的值

-- 设置事务隔离级别为可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 开始事务
START TRANSACTION;
-- 读未提交事务3查询
SELECT * FROM product WHERE id=3;

  • 可重复读事务1再操作

将刚才上一步price更新为99的事务进行提交commit

-- 提交事务
COMMIT;

  • 可重复读事务2再操作

事务1已提交,**去查看产品表id=3的price,结果还是10,也就事务1提交后也是重复读取提交前的10

-- 可重复读事务3查询
SELECT * FROM product WHERE id=3;

4. 串行化 (Serializable)
  • 回顾下串行化概念

串行化确保事务以串行的方式执行,完全避免了并发问题,但可能会降低系统的并发性能。

  • 串行化事务1操作

事务1设置事务隔离级别为串行化,开启事务,修改产品表id=1的price为99,注意这里并未提交事务

-- 设置事务隔离级别为串行化
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 开始事务
START TRANSACTION;
-- 更新表中id=4的产品价格
UPDATE product SET price=99 WHERE id=4;
-- 确认更新成功,读未提交事务4查询
SELECT * FROM product WHERE id=1;

  • 串行化事务2操作

事务2设置事务隔离级别为串行化,去查看产品表id=4的price,结果一直阻塞中等待

-- 设置事务隔离级别为读未提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 开始事务
START TRANSACTION;
-- 读未提交事务2查询
SELECT * FROM product WHERE id=1;

总结

本文通过生动的例子和实际操作,全面解读了MySQL中的四种事务隔离级别:读未提交、读已提交、可重复读和串行化

首先介绍了每种隔离级别的特点及其可能产生的问题,例如脏读、不可重复读和幻读。

接着详细说明了如何在MySQL中设置不同的隔离级别,包括全局设置和会话级别的设置方法

最后通过一系列实操案例,直观展示了不同隔离级别下事务间交互的具体表现,帮助读者理解各种隔离级别的实际应用场景及优缺点。

通过本文的学习,开发者可以更好地掌握事务隔离级别的选择与应用,从而提高数据库应用程序的一致性和性能

🍯猜你喜欢

文章推荐

【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)

【规范】看看人家Git提交描述,那叫一个规矩

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
8天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
22 4
|
6天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
19 1
|
15天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
76 1
|
17天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
59 2
|
20天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
80 4
|
2天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
26 0
|
16天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
46 0
|
1月前
|
存储 SQL 关系型数据库
Mysql学习笔记(二):数据库命令行代码总结
这篇文章是关于MySQL数据库命令行操作的总结,包括登录、退出、查看时间与版本、数据库和数据表的基本操作(如创建、删除、查看)、数据的增删改查等。它还涉及了如何通过SQL语句进行条件查询、模糊查询、范围查询和限制查询,以及如何进行表结构的修改。这些内容对于初学者来说非常实用,是学习MySQL数据库管理的基础。
122 6
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引
|
1月前
|
SQL Ubuntu 关系型数据库
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
本文为MySQL学习笔记,介绍了数据库的基本概念,包括行、列、主键等,并解释了C/S和B/S架构以及SQL语言的分类。接着,指导如何在Windows和Ubuntu系统上安装MySQL,并提供了启动、停止和重启服务的命令。文章还涵盖了Navicat的使用,包括安装、登录和新建表格等步骤。最后,介绍了MySQL中的数据类型和字段约束,如主键、外键、非空和唯一等。
69 3
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用

相关产品

  • 云数据库 RDS MySQL 版