不可重复读的演示
目标
能够解决不可重复读
讲解
不可重复读:一个事务中两次读取的数据内容不一致,要求的是一个事务中多次读取时数据是一致的,这是事务update时引发的问题。
将数据进行恢复:
UPDATE account SET balance = 1000;
-
开启A窗口
set global transaction isolation level read committed;
-
开启B窗口,在B窗口开启事务,并查询数据
start transaction; select * from account;
-
在A窗口开启事务,并更新数据
start transaction; update account set balance=balance+500 where id=1; commit;
-
B窗口查询
select * from account;
两次查询输出的结果不同,到底哪次是对的?不知道以哪次为准。
很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客户,结果在一个事务中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。
解决不可重复读的问题:将全局的隔离级别进行提升为:repeatable read
将数据进行恢复:
UPDATE account SET balance = 1000;
-
A窗口设置隔离级别为:
repeatable read
set global transaction isolation level repeatable read;
-
B窗口退出MySQL,B窗口再进入MySQL,并查询数据
start transaction; select * from account;
-
A窗口更新数据
start transaction; update account set balance=balance+500 where id=1; commit;
-
B窗口查询
select * from account;
结论:同一个事务中为了保证多次查询数据一致,必须使用
repeatable read
隔离级别
幻读的演示
目标
能够解决幻读
讲解
幻读:**是指在一个事务内读取到了别的事务插入的数据,导致前后读取记录行数不同。**这是insert或delete时引发的问题
幻读演示
- 开启A窗口,开启事务,并查询id>1的数据
-
开启B窗口,开启事务,添加一条数据,并提交事务
-
在A窗口修改id>数据的balance为0,并重新查询id>1的数据
我们可以将事务隔离级别设置到最高,以挡住幻读的发生
将数据进行恢复:
UPDATE account SET balance = 1000;
-
开启A窗口
set global transaction isolation level serializable; -- 设置隔离级别为最高
-
A窗口退出MySQL,A窗口重新登录MySQL
start transaction; select count(*) from account;
-
再开启B窗口,登录MySQL
-
在B窗口中开启事务,添加一条记录
start transaction; -- 开启事务 insert into account (name,balance) values ('LaoWang', 500);
-
在A窗口中commit提交事务,B窗口中insert语句会在A窗口事务提交后立马运行
-
在A窗口中接着查询,发现数据不变
select count(*) from account;
-
B窗口中commit提交当前事务
-
A窗口就能看到最新的数据
结论:使用serializable隔离级别,一个事务没有执行完,其他事务的SQL执行不了,可以挡住幻读。
通过提高隔离级别到串行化,可以避免并发访问的所有的问题,但效率太低。
gdv-1562514234369)]
- A窗口就能看到最新的数据
[外链图片转存中…(img-fPRFWNv5-1562514234370)]
结论:使用serializable隔离级别,一个事务没有执行完,其他事务的SQL执行不了,可以挡住幻读。
通过提高隔离级别到串行化,可以避免并发访问的所有的问题,但效率太低。