Mysql ACID 隔离级别 到底什么是幻读

版权声明:本文为博主原创文章,允许转载,请加原文链接。 https://blog.csdn.net/oYueYang1/article/details/81200483

Mysql ACID 隔离级别 到底什么是幻读

1 事物的ACID

ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。一个很好的事务处理系统,必须具备这些标准特性:

1.1 原子性(atomicity)

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

1.2 一致性(consistency)

数据库总是从一个一致性的状态转换到另一个一致性的状态。不会因为系统崩溃而破坏数据库的一致性状态。

1.3 隔离性(isolation)

通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

1.4 持久性(durability)

事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

2 事物的隔离级别

1 read uncommitted 读取尚未提交的数据 :哪个问题都不能解决
2 read committed 读取已经提交的数据 :可以解决脏读 —- oracle默认的
3 repeatable read 重读读取:可以解决脏读 和 不可重复读 —mysql默认的
4 serializable串行化:可以解决 脏读 不可重复读 和 虚读—相当于锁表

3 隔离级别的问题

1、脏读:指一个线程中的事务读取到了另外一个线程中未提交的数据。
2、不可重复读:指一个线程中的事务读取到了另外一个线程中提交的的数据。
3、幻读:在repeatable read 级别中 解决了不可重复读问题,但是带来了幻读问题。幻读其实就是(幻影数据),A事物中所读取的数据只能是事物开始节点的数据快照。在A事物执行中 是不可能读取到数据库里的最新数据的。

-- 事物A
select @@tx_isolation;
-- 读取不提交
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 脏读 A事务可以读取到B事务未提交的数据 
start TRANSACTION;
select * from test;
COMMIT;

-- 读取提交
set SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 不可重复读 A事务可以读取到B事务已经提交的数据 
start TRANSACTION;
select * from test;
COMMIT;
-- 可重复读
set SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 幻读 幻影数据 A事务执行过程中只能读取到事务开始节点的数据快照,而不能读取到数据库最新的数据。
start TRANSACTION;
select * from test;
update test set name='黄忠';
COMMIT;
-- update test set name='黄忠' where id=4;
-- 串行化
set SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 事物B
select @@tx_isolation;
-- 读取不提交
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 脏读
start TRANSACTION;
update test set name='刘备' where id=1;
COMMIT;
-- 读取提交
set SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 不可重复读
start TRANSACTION;
insert into test (id ,name) values(4,'马超');
-- update test set name='黄忠' where id=1;
COMMIT;
-- 可重复读
set SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 幻读
start TRANSACTION;
update test set name='张飞';
-- insert into test (id ,name) values(4,'马超');
-- delete from test where id=4;
COMMIT;
select * from test;
-- 串行化
set SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

4 到底什么是幻读

事物隔离级别带来的 脏读 不可重复读 幻读三个问题,其中 脏读和 不可重复读都很好理解。但是幻读不怎么好理解。
在很多博客中 对幻读的解释不容易理解。其给出的例子有些也不是很准确。
那么到底什么是幻读。
幻读:在repeatable read 级别中 解决了不可重复读问题,但是带来了幻读问题。幻读其实就是(幻影数据),A事物中所读取的数据只能是事物开始节点的数据快照。在A事物执行中 是不可能读取到数据库里的最新数据的。

通过sql理解幻读 (演示的mysql版本为5.6)

4.1 对于insert 操作

-- 事务A
start TRANSACTION;
-- a1
select * from test;
-- a2
update test set name='黄忠';
COMMIT;
-- 事务B
start TRANSACTION;
-- b1
insert into test (id ,name) values(4,'马超');
COMMIT;

原始的数据为3条
这里写图片描述

当A事务 执行 a1 时 查询的是事物开始时的幻影数据 也就是原始数据
在B事务插入一条新数据时,数据库的数据发生改变最新数据为4条
这里写图片描述
由于事务的隔离级别为repeatable read 所以 A事务中看不到数据库里的最新数据。A事务再次查询还是最开始的幻影数据。只有3条。

而当A事务再次执行a2时 你会发现 update 受影响的行为 4条。而你再此执行查询是会发现多了一条数据。
这里写图片描述

幻读对于insert 操作时,A事务执行在update后,select时可以 数据表里对出来一条数据 并且执行了修改操作。

4.2 对于 delete/update 操作

-- 事务A
start TRANSACTION;
select * from test;
-- delete 
update test set name='赵云' where id=3;
-- update
-- update test set name='赵云' where id=1;
COMMIT;
-- 事务B
start TRANSACTION;
-- delete
delete from test where id=3;
-- update
-- update test set name='张飞' where id=1;

COMMIT;

原始的数据为3条
这里写图片描述

当A事务 执行 select 时 查询的是事物开始时的幻影数据 也就是原始数据
在B事务删除id=3的数据时时,数据库的数据发生改变最新数据为2条
这里写图片描述
这时 A事务中看不到数据库里的最新数据。A事务再次查询还是最开始的幻影数据。 3条。
而当A事务修改id=3的数据时 upate 受影响的行为 0条 说明数据已经不存在了
而A事务再次查询是会发现 查询出来的数据还是原始数据 数据并没有改变
这里写图片描述

幻读对于delete操作时,A事务执行update在B事务中删除的数据时,select时可以看到数据并没有改变。
A事务执行update不在B事务中删除的数据时,A事务update操作修改的数据正常,B事务删除的数据仍然存在

这就是repeatable read隔离级别带来的幻读问题(幻影读取)A事务查询的数据只是 A事务开始时那个节点的快照数据。

5 undo redo 日志

undo日志:用于存放数据修改被修改前的值
redo日志:用于记录 数据修改后的记录,顺序记录

猜你喜欢

转载自blog.csdn.net/oYueYang1/article/details/81200483