【MYSQL】四种隔离级别实测

笔者环境(非必须):

MYSQL:5.7.18

操作系统:Mac 11.5.2

设置准备:

#设置事务不要自动提交;默认为1(自动提交)
set @@autocommit = 0;
select @@autocommit;

#设置隔离级别(注意!只在当前查询窗口有效)
set session transaction isolation level READ UNCOMMITTED; #以读未提交为例
show variables like '%tx_isolation%';

=》读未提交 READ UNCOMMITTED

=》读提交 READ COMMITTED

=》可重复读 REPEATABLE READ

=》串行化 SERIALIZABLE

一、读未提交(READ UNCOMMITTED)

#设置隔离级别:读未提交
set session transaction isolation level READ UNCOMMITTED;

设users.age=1;

 执行顺序:

1.1)【事务1】Start Transaction;

1.2)【事务1】SELECT age FROM users WHERE id = 1; #查询结果为1

 

1.3)【事务1】UPDATE users SET age = 2 WHERE id = 1;

1.4)【事务1】SELECT age FROM users WHERE id = 1; #查询结果为2

1.5)【事务2】Start Transaction;(这里需注意,如果事务2是在事务1修改数据之前开启的,下面1.6的步骤读的结果还是修改之前的“1”)

1.6)【事务2】SELECT age FROM users WHERE id = 1;#查询结果为2(读得到其他事务未commit的数据)

 

 ================================ 分割线 =================================

二、读已提交(READ COMMITTED )

#设置隔离级别:读已提交
set session transaction isolation level READ COMMITTED;

设users.age=1;

执行顺序:

2.1)【事务1】Start Transaction;

2.2)【事务1】SELECT age FROM users WHERE id = 1; #查询结果为1

2.3)【事务1】UPDATE users SET age = 2 WHERE id = 1;

2.4)【事务1】SELECT age FROM users WHERE id = 1; #查询结果为2

2.5)【事务2】Start Transaction;

2.6)【事务2】SELECT age FROM users WHERE id = 1;#查询结果为1(读不到其他事务未commit的数据)

 2.7)【事务1】COMMIT;

 2.8)【事务2】SELECT age FROM users WHERE id = 1;#查询结果为2(读得到其他事务已commit的数据)

 ================================ 分割线 =================================

三、串行化(SERIALIZABLE)

串行化,对数据的读写都进行了一个加锁,也就是上一个事务未提交前,后面请求的事务是无法读取/修改数据的;这可很好地保持数据的一致性,但需要放弃并发的使用场景,因此也很少使用这种模式;

我们来实验一下:

设users.age=1;

3.1)【事务1】Start Transaction;

3.2)【事务1】SELECT age FROM users WHERE id = 1; #查询结果为1

3.3)【事务2】SELECT age FROM users WHERE id = 1; #查询结果为1

3.4)【事务1】UPDATE users SET age = 2 WHERE id = 1; #由于事务2没有提交commit,没有办法对数据进行修改,数据被锁,操作等待;

 3.5)【事务2】用commit终止事务

 3.6)【事务1】数据解锁,(3.4)步骤操作成功;

 ================================ 分割线 =================================

四、可重复读(REPEATABLE READ)

 可重复读是数据的默认事务模式,也是我们用得最多的一种模式;

从字面意思可以理解为:

4.1)当数据开启、数据被加载进事务之后,能够在事务中重复被读取,也就是外面的事务对数据进行任何的操作,都不会影响数据在本次事务中的变化;以保证数据在具体一个业务事务中,数据不会突然地被改变,从而保证业务数据的合理性;

4.2)以每个事务提交数据(数据持久化)的顺序,对数据进行一个覆盖;

由于这个模式大家用得很多,就不在这列出实验步骤了;就是开启事务时候,数据只会在当前事务中受影响;不能理解的,可以仿造上面几种模式,自己试下!

五、几种模式下的使用场景:

面试官挺喜欢问这个问题的,笔者其实也没使用过;

本来想给大家搜集一下使用场景的,找了一圈资料后,发现除了我们常用的可重复读(REPEATABLE READ),其他模式的使用场景是真的很少;

我们试着理解一下:

5.1)读未提交&读已提交:

 =》其实这两个模式比较接近,都是能够在事务的过程中,读到其他事务对数据更改的变化;

 =》读未提交(俗称脏读):数据还没提交、也就是数据目前只是存在于mysql的内存中,数据还未被持久化;这种场景下,应该是要对数据有最高时效的读取;也就是数据一旦有任何业务上的变化,都要以“最新”的情况来读取;这个场景下对数据的实时要求比较高,举个不恰当的例子比如:天气、温度、股票、指数等等;(但随着缓存技术的发展,一般这种数据都不会交给数据库来处理了,个人认为!)

=》读已提交:它与脏读的区别点,就是它不认内存里的数据,它至少还是去读已经持久化在硬盘的数据;举个例子:假设,读取实时温度数据时,我希望对温度数据修改之前,同步也要修改湿度的数据才算有效;那么在“修改温度-修改湿度”这个事务提交之前,我还是去读旧的温度/湿度,以免两者不一致,而导致读出来的温度&湿度数据,并非同一时刻的;

5.2)串行化:

=》串行化第一个特征是要放弃掉“并行”的场景;

=》这里有一点要注意的是,大家其实都有阅读的权限。只是当有>=2个事务对资源进行占用时,数据库会给被重复占用资源进行一个加锁;那么这个时候,参与资源暂用的任何一个事务想对数据进行修改都是不行的;除非其他事务相继离去,只剩你自己一个事务还没结束时,你可以对数据进行修改;也正是这个原因,做不到数据并发地修改;

=》这种模式下,简直有点像对其他“不严谨”的模式的一种报复性心理的设计(哈哈哈!);可以想象这种模式下,对程序员控制锁的能力要求略高,因为你必须确保,当前业务只有一个访问者对其读写,否则数据库就很容易进入死锁;

=》好处是,数据一致性是很高的,不会出现数据紊乱的情况;

=》但使用前提是,你的场景不需要并发&你可以很好地控制锁、避免死锁的发生!

以上是对MYSQL数据库事务四种模式的实验,以及个人理解,

如有笔误、不对的、或理解偏差的地方,欢迎指出、一起交流学习!

纸上得来终觉浅,

希望对你有帮助!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值