3.mysql之事务的隔离性详解

事务机制

事务的四个隔离级别

  • 读取未提交的数据
  • 读取已提交的数据
  • 重复读取
  • 序列化

事务选择哪个隔离级别是根据具体的业务场景来使用的,并没有哪个绝对的好坏

读取未提交的数据

比如下面的案例:

  1. 前提:买票系统中的某个座位还未售出:D座
  2. A事务读取到D座未售出状态,然后将他改成已售出,但是此时这个事务还没有提交,只是A事务的redo日志中显示已售出
  3. 此时B事务看到D座未售出状态,然后将他改成已售出并且在A之前提交了事务;
  4. 那么A事务在提交的时候因为此时的座位状态已经被改变,因此A事务就触发了回滚,这种情况对于用户来说,体验上不好
  5. 那么此时就需要在A事务改变数据但是还未提交事务前,B事务可以读取A事务的临时文件,也就是A事务的redo日志,当B事务发现这个状态是已售出就不会购买D座,它可以去购买E座,这样就不会引发事务的冲突了
  6. 这种情况可以使用的隔离级别就是:读取未提交数据

修改事务隔离级别:以读取其他事务未提交的数据

  • read uncommitted
  • 会话:Navicat中打开一个查询面板,这个相当于一次会话,关闭这个查询面板就是关闭了这次会话
  • 用法:设置当前会话的隔离级别,隔离级别只是针对当前会话的,不是全局的
set session transaction isolation level read uncommitted

栗子:
打开Navicat,有下面的表:
score:
在这里插入图片描述

打开3个查询面板
面板1,A事务修改表中grade为100,但是不提交事务

start transaction;
update score set grade=100;
select * from score;

此时事务内读取到的是修改后的数据
在这里插入图片描述

面板2,B事务,不设置隔离级别,直接读取表数据:

start transaction;
select * from score;

这里默认读取的是已提交的数据,这里看到数据并未修改,因为A事务还没有提交
在这里插入图片描述

面板3,C事务,设置隔离级别:读取其他事务未提交的数据

set session transaction isolation level read uncommitted;
start transaction;
select * from score;

根据结果可以看到读取的是A事务还未提交的数据
在这里插入图片描述

读取已提交数据

比如下面的案例:

  1. 原本的账户中有1000元
  2. 若是A事务给账号添加1000元,此时redo日志中账户金额是2000,
  3. B事务是取出100元,且在A事务未提交前读取未提交的数据,那此时就是1900
  4. 若是A事务因为一些原因最终回滚了,然后B事务又提交了,那此时的1900元的数据就是有问题的
  5. 因此,这种银行业务,读取用户当前账号中的金额绝对不能读取未提交的数据,而是读取已提交的数据

修改事务隔离级别为:只能读取其他事务提交的数据

  • read committed

具体用法:

set session transaction isolation level read committed

栗子:

接着前面的栗子,A事务还未修改,此时打开一个新查询面板,创建C事务,设置读取已提交的数据

set session transaction isolation level read committed;
start transaction;
select * from score;

根据结果,可以看到读取的是已提交的数据,A事务还未提交,修改的数据还未同步:
在这里插入图片描述

重复读取

  1. 如果淘宝上一个商品,用户在下单后(还未支付前),商品的价格发生了变化,那么这种情况一般的是更改后的商品价格不会影响更改前已下单的商品价格
  2. 比如说A事务是下单商品,但是这个事务还未提交,此时B事务给商品涨价了,那么不论B事务是否提交,A事务数据的读始终都是下单时的价格(即A事务undo日志中的数据)
  3. 也就是说A事务一旦开启,其他事务进行的操作不会影响到A事务的数据

修改事务的隔离级别:事务在执行中反复读取数据,得到的结果是一致的,不会受其他事务影响

  • repeatable read

具体用法:

set session transaction isolation level repeatable read

栗子:

Navicat中2个面板:

面板1,A事务,读取表中数据:

set session transaction isolation level repeatable read;
start transaction;
select * from score;

在这里插入图片描述

面板2,B事务,修改表中数据并提交事务:

start transaction;
update score set grade=100;
select * from score;
commit;

此时表中数据被修改了:
在这里插入图片描述

面板1,删除前2条数据,保留一条查询,查看表数据

select * from score;

表中仍然是A事务开始时的数据
在这里插入图片描述

事务的序列化

  • 由于事务并发执行所带来的各种问题,前三种隔离级别只使用在某些业务场景中,但是序列化的隔离性,让事务逐一执行,就不会产生上述问题了
  • 这种情况下事务不能并发执行,使用的比较少
set session transaction isolation level serializable

栗子:

Navicat中2个面板

面板1,A事务,会话隔离性设置成序列化

set session transaction isolation level serializable;

面板2,B事务,开启事务后不提交事务:

start transaction;
update score set grade=200;
select * from score;

面板1,查询语句,执行后发现没有出现查询结果,这是因为B事务还未提交,A事务不能执行:

select * from score;

面板2,提交事务后,此时面板1中的查询结果出现了

commit;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值