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 (串行化)

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

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

左窗:

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

文章创作不易

求点赞!

求评论!

求收藏!

相关推荐
钢铁男儿32 分钟前
PyQt5高级界而控件(容器:装载更多的控件QDockWidget)
数据库·python·qt
阿蒙Amon3 小时前
C# Linq to SQL:数据库编程的解决方案
数据库·c#·linq
互联网搬砖老肖7 小时前
运维打铁: MongoDB 数据库集群搭建与管理
运维·数据库·mongodb
典学长编程8 小时前
数据库Oracle从入门到精通!第四天(并发、锁、视图)
数据库·oracle
积跬步,慕至千里9 小时前
clickhouse数据库表和doris数据库表迁移starrocks数据库时建表注意事项总结
数据库·clickhouse
极限实验室9 小时前
搭建持久化的 INFINI Console 与 Easysearch 容器环境
数据库
星辰离彬9 小时前
Java 与 MySQL 性能优化:Java应用中MySQL慢SQL诊断与优化实战
java·后端·sql·mysql·性能优化
白仑色10 小时前
Oracle PL/SQL 编程基础详解(从块结构到游标操作)
数据库·oracle·数据库开发·存储过程·plsql编程
程序猿小D11 小时前
[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的个人财务管理系统,推荐!
java·数据库·mysql·spring·毕业论文·ssm框架·个人财务管理系统
钢铁男儿12 小时前
C# 接口(什么是接口)
java·数据库·c#