MySQL事务的隔离级别问题之脏读
1. 脏读
所谓的脏读就是指⼀个事务读取了另⼀个事务未提取的数据。
试想⼀下:a账户要给b账户100元购买商品,如果a账户开启⼀个事务,执⾏下⾯的update语句做了如下转账的⼯作:
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
如果a账户先不提交事务,通知b账户来查询,由于b的隔离级别⽐较低,此时就会读取a事务中未提交的数据,发现a确实给⾃⼰转了100元,然后给a 发货,等b发货成功之后,a再将事务回滚,此时b就会受到损伤,这就是脏读造成的。
为了演⽰上⾯的情况,这⾥我们开启了两个命令⾏窗⼝(相当于开启两个线程),分别模拟a账户和b账户,如下:
(1)设置b账户中事务的隔离级别
⼤家都知道MySQL的默认隔离级别是Repeatable Read(可重复读),该级别是可以避免脏读的,因此需要将b账户中事务的隔离级别设置为Read Uncommitted(读未提交),具体语句如下:
mysql怎么读英语>shell脚本求1到100的和set session transaction isolation level read uncommitted;
如下:
上述语句之中,session表⽰当前会话,transaction就表⽰事务,isolation表⽰隔离,level表⽰级别,read uncommitted表⽰当前的隔离级别,该语句执⾏成功之后,使⽤select语句查询事务的隔离级别,结果如下:
select @@tx_isolation;
如下:
从上述结果可以看出,b账户的事务隔离级别以及修改为Read Uncommitted,接下来就是演⽰脏读的情况
2)演⽰脏读
b账户:为了证明出现了脏读的情况,⾸先在b账户中开户⼀个事务,并在该事务中查询当前账户的余额信息,查询结果如下:
start transaction;
parseint在javaselect * from account;
如下:
手机端打开html文件摩托罗拉java游戏大全a账户:在a账户中开启⼀个事务,并在当前窗⼝中执⾏转账功能,具体语句如下:
start transaction;
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
如下:
需要注意的是:此时不要提交事务,如果提交事务就⽆法演⽰出现脏读的情况。
b账户:a账户执⾏完转账语句后,b账户查询当前账户,如下:
从上⾯的查询结果来看,a账户已经成功给b账户转账了100元,这是由于b账户的事务隔离级别⽐较低,因此才读取了a账户还没有提交的数据内容,出现了脏读的情况,这时候,b误以为a账户以及转账成功,便会给a发货,当b发货之后a如果不提交事务将事务回滚,b就会受到损失。
上⾯演⽰完毕了,需要将a账户中的事务回滚,b账户中的事务提交。
(3)设置b账户的事务隔离级别
为了防⽌脏读发⽣,可以将b账户中的事务隔离级别设置为Read Committed(读提交),该级别会避免脏读,具体语句如下:
set session transaction isolation level read committed;
上述的语句执⾏成功之后,b账户的隔离级别已经设置成Read Committed
(4)验证是否出现脏读
b账户:为了说明没有出现脏读的情况,⾸先要在b账户中开启⼀个事务,并在该事务中查询各账户的余额情况,查询结果如下:
a账户:在a账户中重新开启⼀个事务,实现了转账功能,如下:
start transaction;
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
b账户:当a 账户转账成功之后,可以在b账户中再次查询各账户的余额信息,查询结果如下:
通过上⾯的对⽐两次查询结果可以发现,b账户在同⼀个事务中的查询结果是⼀致的,并没有查询到a账户中未提交的内容,因此可以说明Read Committed 隔离级别可以避免脏读,最后分别将a账户和b账户中的事务回滚.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论