MySQL并发事务问题及隔离级别演示

举例演示了MySQL的并发事务问题,以及四个事务隔离级别的区别,例子直接跳转标题3.

1.并发事务问题

(1)脏读 (Dirty Read)

  • 问题描述 :一个事务读取了另一个未提交事务修改过的数据

  • 示例

    • 事务A修改了某行数据但未提交

    • 事务B读取了事务A修改后的数据

    • 事务A回滚,事务B读取的数据就是无效的"脏数据"

(2)不可重复读 (Non-repeatable Read)

  • 问题描述 :在同一事务内,多次读取同一数据返回不同结果(因为其他事务修改并提交了该数据)

  • 示例

    • 事务A第一次读取某行数据

    • 事务B修改了该行数据并提交

    • 事务A再次读取同一行数据,发现数据已改变

(3) 幻读 (Phantom Read)

  • 问题描述 :在同一事务内,多次查询返回不同的行集合(因为其他事务新增或删除了数据)

  • 示例

    • 事务A查询表中符合某条件的行

    • 事务B插入新的符合该条件的行并提交

    • 事务A再次查询,发现多出了"幻影行"

2.事务隔离级别

我们可以通过给事务设置隔离级别来解决上述并发问题

MySQL 提供了四种隔离级别

隔离级别 脏读 不可重复读 幻读 说明
READ UNCOMMITTED (读未提交) 可能 可能 可能 最低隔离级别,性能最好但问题最多
READ COMMITTED (读已提交) 可能 可能 不可能 只读取已提交的数据,Oracle默认级别
REPEATABLE READ (可重复读) 可能 不可能 不可能 MySQL默认级别,确保同一事务内读取一致
SERIALIZABLE (串行化) 不可能 不可能 不可能 最高隔离级别,性能最差但最安全

事务隔离级别的相关操作

查看当前隔离级别

sql 复制代码
SELECT @@transaction_isolation;
-- 或
SHOW VARIABLES LIKE 'transaction_isolation';

设置隔离级别

可以设置全局级别或会话级别:

sql 复制代码
-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

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

-- 设置下一个事务的隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

3.操作演示

(1).准备数据

首先,准备一个简单的数据表做演示

这里是一个简单的账户表

sql 复制代码
create table account
(
    user_name varchar(20) not null,
    money     double      null,
    id        int auto_increment
        primary key
);

# 添加数据
insert into account values ('jack',8000,1),('mary',8000,2);

因为要演示并发问题,所以,我们直接使用cmd打开两个窗口演示

找到 上面表所在的数据库

(2).脏读

我们先演示,脏读:一个事务读取了另一个未提交事务修改过的数据

先设置左窗口的事务隔离级别为 read uncommitted

sql 复制代码
set session transaction isolation level read uncommitted ;

然后在左窗开启一个事务,查询一下 account表的数据:

接着在右窗开启一个事务,修改 一下 account表的数据:

注意,这时我们并没有commit 提交右窗修改的数据

但是,我们再在左窗查询 数据,却发现查询到的数据已经修改了

这就体现了脏读问题,右窗的事务,访问到了左窗事务还未提交的数据!

演示完成,别忘了结束两边的事务,再进行后续操作

我们把右窗事务隔离级别修改为 readcommited 就可以避免脏读问题

就是下面 不可重复读的操作演示,不再赘述

右窗:

左窗:

(3.1).不可重复读

右窗事务隔离级别设置为 readcommited

开启一个事务,查询一下数据

在左窗开启一个事务,修改表中数据

左窗还未提交zai再次在右窗查询,发现数据没有变化,也就是解决了 脏读问题

左窗提交数据后再次在右窗查询,发现数据变化了,

在右窗的一个事务过程中,出现了多次读取同一数据但返回不同结果的现象,这就是不可重复读

(3.2)解决不可重复读

设置右窗事务隔离级别为REPEATABLE READ (可重复读), 开启一个事务,查询当前表数据

左窗还是开启一个事务,修改表中数据,这次我们直接提交!

右窗再次查询表数据,可以看到,这次左窗事务虽然已经提交了修改,但是右窗查询数据还是没变。 这样一个事务里就不会出现多次读取同一数据但返回不同结果的现象,这就解决了上面 不可重复的的问题

我们结束右窗事务后,再次查询,则看到了最新数据

(4.1).幻读

右窗不改变隔离级别,依旧为 repeatable read

开启新事务,查询id为3的信息,当前没有id为3的人,当然查询不到

此时,左窗开启一个事务,插入id= 3的一条数据 ,并直接提交

由于,并发执行,之前右窗没有查询到id= 3的数据,于是也准备插入一条id= 3的数据,但是由于左窗已经插入完成,所以无法插入。如下图

右窗再次查询id为3的信息,但是还是查询不到

像这样右窗这样,查询时查询不到,插入时又认为数据已经存在不让插入 的现象 就叫 幻读

(4.2).解决幻读

设置右窗事务隔离级别为SERIALIZABLE (串行化),开启事务,查询id= 4的数据,没有

左窗开启事务,插入id= 4的一条数据,但是按回车后,却没有运行,这就是因为 右窗事务隔离级别为SERIALIZABLE (串行化)

  • 所有事务只能串行执行,解决了所有并发问题

只能在右窗执行完当前事务的全部操作后,左窗事务才能继续!

左窗:

=================结束==================

文章创作不易

求点赞!

求评论!

求收藏!

相关推荐
Jay Kay1 小时前
跳跃表可视化深度解析:动态演示数据结构核心原理
数据结构·数据库
千册4 小时前
python+pyside6+sqlite 数据库测试
数据库·python·sqlite
java叶新东老师6 小时前
PowerDesigner 画ER图并生成sql 教程
数据库·sql
Jonariguez6 小时前
Mysql InnoDB存储引擎
数据库·mysql
nbsaas-boot7 小时前
SQL Server 窗口函数全指南(函数用法与场景)
开发语言·数据库·python·sql·sql server
Y.ppm7 小时前
数分思维12:SQL技巧与分析方法
数据库·sql
森叶7 小时前
Claude Code 安装向量数据库MCP服务
数据库
bestsun9997 小时前
Time drifts can result in unexpected behavior such as time-outs.
数据库·oracle
waveee1238 小时前
学习嵌入式的第三十四天-数据结构-(2025.7.29)数据库
数据结构·数据库·学习
何传令9 小时前
SQL优化系统解析
数据库·sql·mysql