所谓脏读就是说,两个事务,其中一个事务能读取到另一个事务未提交的数据。
场景:session1要转出200元,session2转入100元。基数为1000。顺利完成正确的结果应该是900元。但是我们假设session2转入因为某种原因事务回滚。这时正确的结果应该是800元。
演示步骤:
① 新建两个session(会话,在navicat中表现为两个查询窗口,在mysql命令行中也是两个窗口),分别执行
select @@tx_isolation;//查询当前事务隔离级别 2 set session transaction isolation level read uncommitted;//将事务隔离级别设置为 读未提交
② 两个session都开启事务
start transaction;//开启事务
③ session1和session2:证明两个操作执行前账户余额为1000
select * from tb_bank where id=1;//查询结果为1000
④ session2:此时假设session2的更新先执行。
update tb_bank set account = account + 100 where id=1;
⑤ session1:在session2 commit之前session1开始执行。
select * from tb_bank where id=1;//查询结果:1100
⑥ session2:因为某种原因,转入失败,事务回滚。
rollback;//事务回滚 2 commit;//提交事务
⑦ 这时session1开始转出,并且session1觉得⑤中查询结果1100就是正确的数据。
update tb_bank set account=1100-200 where id=1; 2 commit;
⑧ session1 和 session2查询结果
select * from tb_bank where id=1;//查询结果:900
这时我们发现因为session1的脏读造成了最终数据不一致。正确的结果应该为800;
到此我们怎么避免脏读呢,将事务的隔离性增加一个级别到read-commit
重置数据,使数��恢复到account=1000
① 新建两个session,分别设置
set session transaction isolation level read committed;//将隔离级别设置为 不可重复读
重复执行(1)中的②③④步
⑤ session1执行查询
select * from tb_bank where id=1;//查询结果为1000,这说明 不可重复读 隔离级别有效的隔离了两个会话的事务。
这时我们发现,将事务的隔离升级为read-committed;后有效的隔离了两个事务,使得session1中的事务无法查询到session2中事务对数据的改动。有效的避免了脏读。
2、通过sql演示-----read-committed的不可重复读 (1)read-commit的不可重复读重置数据,使数据恢复到account=1000
所谓的不可重复读就是说,一个事务不能读取到另一个未提交的事务的数据,但是可以读取到提交后的数据。这个时候就造成了两次读取的结果不一致了。所以说是不可重复读。
READ COMMITTED 隔离级别下,每次读取都会重新生成一个快照,所以每次快照都是最新的,也因此事务中每次SELECT也可以看到其它已commit事务所作的更改
场景:session1进行账户的查询,session2进行账户的转入100。
session1开启事务准备对账户进行查询然后更新,这时session2也对该账户开启了事务进行更新。正确的结果应该是在session1开启事务以后查询读到的结果应该是一样的。
① 新建两个session,分别设置
set session transaction isolation level read committed;
② session1和session2分别开启事务
start transaction;
③ session1第一次查询:
select * from tb_bank where id=1;//查询结果:1000
④ session2进行更新: