MySQL事务的四大隔离级别

本文详细介绍了MySQL事务的四大隔离级别:读未提交、读已提交、可重复读和串行化,以及在各个级别下可能出现的问题,如脏读、不可重复读和幻读。通过实例分析了各隔离级别的并发问题,并探讨了MySQL如何通过MVCC等机制实现这些隔离级别,以确保数据的一致性和安全性。
摘要由CSDN通过智能技术生成


在这里插入图片描述

(一)事务

什么是事务?

事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。

事务的四大特性

  • 原子性: 事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。
  • 一致性: 指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
  • 隔离性: 多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。。
  • 持久性: 表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。

(二)事务并发存在的问题

事务并发执行存在什么问题呢,换句话说就是,一个事务是怎么干扰到其他事务的呢?看例子吧~

假设现在有表:

CREATE TABLE `account` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `balance` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `un_name_idx` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

复制代码表中有数据:
在这里插入图片描述

脏读(dirty read)

假设现在有两个事务A、B:

  • 假设现在A的余额是100,事务A正在准备查询Jay的余额
  • 这时候,事务B先扣减Jay的余额,扣了10
  • 最后A 读到的是扣减后的余额
    在这里插入图片描述由上图可以发现,事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读

不可重复读(unrepeatable read)

假设现在有两个事务A和B:

  • 事务A先查询Jay的余额,查到结果是100
  • 这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务
  • 事务A再去查询Jay的账户余额发现变成了90
    在这里插入图片描述
    事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。

幻读

假设现在有两个事务A、B:

  • 事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录
  • 这时候,事务B开启,插入一条id=4的记录,并且提交了
  • 事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。
    在这里插入图片描述

事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。

(三)事务的四大隔离级别实践

既然并发事务存在脏读、不可重复、幻读等问题,InnoDB实现了哪几种事务的隔离级别应对呢?

  • 读未提交(Read Uncommitted)
  • 读已提交(Read Committed)
  • 可重复读(Repeatable Read)
  • 串行化(Serializable)

读未提交(Read Uncommitted)

想学习一个知识点,最好的方式就是实践之。好了,我们去数据库给它设置读未提交隔离级别,实践一下吧~
在这里插入图片描述
先把事务隔离级别设置为read uncommitted,开启事务A,查询id=1的数据

set session transaction isolation level read uncommitted;
begin;
select * from account where id =1;

结果如下:
在这里插入图片描述
这时候,另开一个窗口打开mysql,也把当前事务隔离级别设置为read uncommitted,开启事务B,执行更新操作

set session transaction isolation level read uncommitted;
begin;
update account set balance=balance+20 where id =1;

接着回事务A的窗口,再查account表id=1的数据,结果如下:
在这里插入图片描述
可以发现,在读未提交(Read Uncommitted) 隔离级别下,一个事务会读到其他事务未提交的数据的,即存在脏读问题。事务B都还没commit到数据库呢,事务A就读到了,感觉都乱套了。。。实际上,读未提交是隔离级别最低的一种。

读已提交(READ COMMITTED)

为了避免脏读,数据库有了比读未提交更高的隔离级别,即读已提交。
在这里插入图片描述
把当前事务隔离级别设置为已提交读(READ COMMITTED),开启事务A,查询account中id=1的数据<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值