MySQL事务隔离级别(2022.05.15)
Posted Mr. Dreamer Z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL事务隔离级别(2022.05.15)相关的知识,希望对你有一定的参考价值。
事务是什么?
一般是指要做的或所做的事情
为什么要引入事务?
为了保证工作流程中操作的数据的可靠性
原子性(Atomicity):指的是事务是一个不可分割的单位,要么事务中的所有的操作全部成功,要么全部失败;——操作层面
一致性(Consistency):和原子性类似,只不过在数据层面。指的是事务必须在执行前后满足数据库的所有约束。(这个约束我认为是指:有一个操作,其中A,B,C三步都需要修改数据,那么这三步操作数据要么都成功,要么都失败。成功或者失败得到的数据结果就代表数据库的约束)
隔离性(isolation):不同事务之间的操作,互不影响
持久性(durability):数据一经提交永久保存
目录
1.隔离性
隔离性分为四个隔离级别:读未提交、读已提交,可重复读、串行化。
事务的隔离级别
由上图我们可得知不同隔离级别带来的问题。
下面,让咱们来亲自动手试试,毕竟不断地重复才能加深我们的映像!话不多说,开始
查看当前事务隔离级别
select @@tx_isolation;
先创建一个表,丢几条数据进去
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `account` (`name`, `balance`) VALUES ('lilei', '450');
INSERT INTO `account` (`name`, `balance`) VALUES ('hanmei', '16000');
INSERT INTO `account` (`name`, `balance`) VALUES ('lucy', '2400');
1.1 读未提交
根据上图可知,读未提交这个隔离级别是最低级的隔离级别了。
它会造成:脏读、不可重复读、幻读。
咱们来看看脏读是怎么一回事:
脏读:事务A读取到了事务B修改但未提交的数据
先设置隔离级别为读未提交
set tx_isolation='read-uncommitted';
咱看看原始的数据先
客户端A开启事务
修改数据;但还未提交
客户端B开启事务之后查看,发现此时,读到了客户端A修改但是还未提交的数据。
然后客户端A操作回滚
客户端B再去查询,发现依旧读取到了未提交的数据
以上现象就是脏读;
1.2 读已提交
在该隔离级别中,会造成:不可重复读、幻读;
不可重复读:当前事务在单位时间内连续两次读取数据,发现两次读到的数据结果都不一致;
首先,先将隔离级别改为读已提交
set tx_isolation='read-committed';
然后,在客户端A开启事务改动数据,但是不提交
在客户端B查询
此时我们发现,客户端B读取到的还是之前的数据,并未读到事务1修改但未提交的数据,避免了脏读现象。
接着,客户端A提交事务
在客户端B中进行查询,发现两次得到的结果不一样
这就是不可重复读
1.3 可重复读
在可重复读这一隔离级别,会产生幻读
幻读:简单来说,就是在当前事务进行读操作,第一次读,发现总共有3条数据。第二次读,就发现有不等于3条数据的数量。
咱们先将隔离级别改为可重复读(MySQL默认的隔离级别)
set tx_isolation='repeatable-read';
先试试,能不能解决不可重复读呢?
在客户端A中开启事务修改数据,然后提交事务。
然后在客户端B中进行查看
发现不可重复读问题已经解决了。
咱们再来看看,幻读的问题
客户端A新增一条数据之后,提交事务
客户端B进行查询
发现两次读到的数据条数不一样了,这就是幻读;
1.4 可串行化
这是最高等级的隔离级别,能够解决所有问题。
设置隔离级别
set tx_isolation='serializable';
客户端A上进行查询操作,针对id=1的数据
然后在客户端B进行更新,也针对id=1的数据
但是呢,发现id=1的数据已经被锁了。
咱们来试试id=2的数据,能否被修改吗。
发现是没有问题。
那么先修改再查询呢?
还是不行。。。。
那是为什么会这样呢?先上结论
如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围(就算该行数据还未被插入也会加锁,这种是 间隙锁 )都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读。 感觉有点乱呢,让我们通过例子来理一理 这是咱们的数据id为1,4,6. 那么对应的区间是[1,4],[4,6],[6,+∞)
客户端A修改id>1且id<7的数据
客户端B查询id=4的数据
发现无法查询,其原因就是因为间隙锁将对应区间的数据给锁住了。别着急,接着往下看
再来试试,客户端A修改id>1且id<5的数据
事务2查询id=6的数据
发现还是锁住了,咋不对呢?我明明没有修改这个范围内的数据啊!
这就是所谓的间隙锁了
刚刚提到,咱们当前数据对应的区间是[1,4],[4,6],[6,+∞)。那我修改的是(1,5)的数据,为啥还是不能修改id=6的数据呢?
原因就是因为id=6的数据,在[4,6]这个区间。所以,id=6这条数据就被锁住了。
那么id=7的数据可以插入吗?
那么咱们继续试试嘛,插入一条id=7的数据。
插入成功之后,客户端A还是修改区间(1,5)的数据
客户端B我们来查询id=7的数据,以及查询id=4的数据
按照上图的结果,可以验证我们刚才所说的,间隙锁锁住的区间。所以id=7可以查询,id=4不能。
~stay hungry,stay foolish
以上是关于MySQL事务隔离级别(2022.05.15)的主要内容,如果未能解决你的问题,请参考以下文章