当前位置: 首页 > article >正文

MySQL-事务隔离级别

1. MySQL事务的四种隔离级别

1.1 读未提交(READ UNCOMMITTED)

READ UNCOMMITED提供了事务之间最小限度的隔离,除了幻读和不可重复读取的操作外,处于这个隔离级别的事务可以读到其它事务还未提交的数据。

1.2  读已提交(READ COMMITTED)

处于READ COMMITTED隔离级别的事务可以读取到其它事务对数据的修改。也就是说,在处理事务期间,如果其他事务修改了相应的表(已提交),那么同一个事务的多次SELECT执行可能返回不同的结果。

1.3 可重复读(REPEATABLE READ)

可重复读隔离级别上,当前正在执行事务的变化不能被其它事务看到,也就是说,同一个事务的多次SELECT执行结果是相同的。

1.4 串行化(SERIALIZABLE)

串行化,事务之间一个接一个的执行,这种隔离级别提供了事务之间最大限度的隔离。

2. 通过例子理解脏读、不可重复读、幻读

2.1 读未提交隔离级别下脏读、不可重复读、幻读

2.1.1 准备测试数据

设置事务隔离级别为READ UNCOMMITTED

-- 在DBeaver打开2个SQL编辑窗口(不同的session),各执行如下语句。
-- 将两个SESSION的事务隔离级别设置为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

创建一张用户表t_user,预插入两条数据,如表格:

2.1.2 脏读

脏读,在一个事务中可以读取到另一个事务还未提交的数据。

窗口A

--事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: COMMIT;

窗口B

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: COMMIT;

测试步骤:

a) 窗口A执行line1, line2, 插入用户“王五”,先不执行提交

b) 窗口B执行line1,line2时,可以看到用户“王五”,而此时窗口A尚未提交事务,产生了脏读

2.1.3 不可重复读

不可重复读,在一个事务中多次执行SELECT语句,返回的结果不相同。

A窗口

-- 事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: INSERT INTO t_user(id, user_name, balance) VALUES (4, '赵六', 1000);
line4: COMMIT;

B窗口

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: SELECT * FROM t_user;
line4: COMMIT;

执行步骤

a) A窗口执行line1, line2语句,B窗口执行line1, line2语句,此时B窗口可以读取到“王五”。

b) A窗口接着执行line3, B窗口执行line3,此时B窗口可以读取到“王五”和“赵六”

两次SELECT查询结果不一致,所以是不可重复读

2.1.4 幻读

幻读与不可重复读比较像。事务比做人的话,就是当前事务产生幻觉了。

窗口A

--事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: COMMIT;

窗口B

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: DELETE FROM t_user WHERE id = 3;
line4: COMMIT;

执行步骤

a) A窗口执行line1, line2,B窗口执行line1, line2 , 可以读取到“王五”

b) B窗口继续执行line3,发现执行删除操作一直在等待,无法完成删除。原因是因为id=3的记录在窗口A尚未提交,脏读导致可以被窗口B看到,所以是无法删除的。此时就产生了幻觉,明明有id=3的记录,却无法删除。

2.2 读已提交隔离级别下脏读、不可重复读、幻读

2.2.1 设置事务隔离级别为READ COMMITTED

-- 在DBeaver打开2个SQL编辑窗口(不同的session),各执行如下语句。
-- 将两个SESSION的事务隔离级别设置为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

2.2.2 脏读

窗口A

--事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: COMMIT;

窗口B

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: COMMIT;

执行步骤:

a) 窗口A执行line1, line2 ,窗口B执行line1, line2看不到用户“王五”

b) 窗口A执行line3, 窗口B再次执行line2,此时可以看到用户“王五”,所以不存在脏读问题

2.2.3 不可重复读

窗口A

--事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: COMMIT;

窗口B

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: COMMIT;

执行步骤:

a) 窗口B执行line1, line2,此时看不到用户“王五”

b) 窗口A执行line1, line2, line3

c) 窗口B再次执行line2,此时可以看到用户“王五”,两次SELECT的结果不一致,所以是不可重复读

2.2.4 幻读

窗口A

--事务A
line1: START TRANSACTION;
line2: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line3: COMMIT;

窗口B

-- 事务B
line1: START TRANSACTION;
line2: SELECT * FROM t_user;
line3: INSERT INTO t_user(id, user_name, balance) VALUES (3, '王五', 1000);
line4: COMMIT;

执行步骤:

a) 窗口B执行line1,line2,此时没有看到用户“王五”

b) 窗口A执行line1, line2, 插入用户“王五”

c) 窗口B执行line3时会一直等待窗口A的事务提交或回滚。在这里窗口B产生了幻觉,明明执行SELECT没有看到用户“王五”,但是插入不成功。

2.3 REPEATABLE READ

和READ COMMITTED相比,REPEATTED READ进一步解决了不可重复读问题,但是幻读则未能解决。REPEATABLE READ中关于幻读的测试与上一小节基本一致,不同的是在步骤b中执行到line3提交事务。由于REPEATABLE READ已经解决了不可重复读,因此步骤b即使提交了事务,SELECT也查不出已经提交的数据。继续插入会报错。

2.4 SERIALIZABLE

SERIALIZABLE提供了事务之间最大限度的隔离,在这种隔离级别中,事务一个接一个的顺序执行,不会发生脏读,不可重复读以及幻读,最安全。

如果设置当前事务隔离级别为SERIALIZABLE,那么此时开启其它事务时,就会阻塞,必须等当前事务结束了,其它事务才能开启成功,因此前面的脏读,不可重复读,幻读问题在这个隔离级别下不会发生。

3. 总结

3.1 隔离级别与脏读、不可重复读、幻读的关系如下

隔离级别脏读不可重复读幻读
READ UNCOMMITTED允许允许允许
READ COMMITTED不允许允许允许
REPEATABLE READ不允许不允许允许
SERIALIZABLE不允许不允许不允许

3.2 隔离级别与性能之间的关系


http://www.kler.cn/news/366587.html

相关文章:

  • 【K8S系列】Kubernetes Service 基础知识 详细介绍
  • 2024Flutter面试题
  • Python 从入门到实战39(线程间的通信)
  • .NET使用QuestPDF高效地生成PDF文档
  • Github优质项目推荐(第八期)
  • 时序数据库 TDengine 支持集成开源的物联网平台 ThingsBoard
  • 不用一行代码,手把手叫你创作一款旅游类智能体!
  • CANFD SSP第二采样点引发的“风波”分析
  • 完美解决phpstudy安装后mysql无法启动
  • React六官方文档总结三脱围机制
  • 关闭容器 禁用docker自启动 卸载docker
  • go 使用fyne实现桌面程序的计算器例子
  • 2024年土建施工员考试题库及答案
  • Android常用C++特性之std::piecewise_construct
  • Java基础(7)图书管理系统
  • 网站渗透常识
  • Modern CMake 简明教程(8)- 集成Qt
  • lua while循环
  • Linux -- 共享内存(2)
  • 机器学习4
  • ESC服务器被暴力破解如何解决
  • Redis 主从同步 总结
  • 【大数据技术基础 | 实验五】ZooKeeper实验:部署ZooKeeper
  • LDAP 部署手册
  • 每日一题——第一百一十九题
  • 多线程——线程池