查看系统当前隔离级别??select @@global.tx_isolation;
repeatable read(MySQL默认隔离级别,也就是可重复读)
以下是事务隔离级别图
隔离级别 | 脏读 | 不可重复读 | 幻读 | 读未提交read-uncommitted | 有 | 有 | 有 | 读已提交read-committed | 无 | 有 | 有 | 可重复读repeatable-read?(默认) | 无 | 无 | 有 | 序列化(一条条地进行)serializable | 无 | 无 | 无 |
?读未提交read-uncommitted? ?:事务A里面读到事务B未提交(commit)的数据
读已提交read-committed :?事务A里面读到事务B已经提交(commit)的数据
可重复读repeatable-read?(默认) :解决了读未提交和读已提交,但是会出现幻读,会事务A里面第一次能读取到事务B最新提交的数据
幻读 事务A里面读取到了事务B新增的记录(事务B有commit)
序列化(一条条地进行)serializable
winiis_account?表结构
读未提交read-uncommitted set global ????tx_isolation='read-uncommitted' show variables like 'tx_isolation' select * from winiis_account where username=866700?????结果 700 | 读未提交read uncommitted set global ????tx_isolation='read-uncommitted' show variables like 'tx_isolation' select * from winiis_account where username=866700?????结果 700 | start TRANSACTION ? | start TRANSACTION | select * from winiis_account where username=866700?????结果 700 ?第一次查询的是700 | update winiis_account set balance=balance-50 where username='866700'?//结果650 | select * from winiis_account where username=866700?????结果 650 第二次查询的是650,两个结果不一样,在事务A里面查询到事务B未commit的数据,假如事务B做rollback操作、650就变成了700,而我们程序用了700的值做往下的计算,导致bug | select * from winiis_account where username=866700?????结果 650 | Commit | Commit | select * from winiis_account where username=866700?????结果 650 | select * from winiis_account where username=866700?????结果 650 |
读已提交read-committed??不可重复读(第一次读700 ?第二次读是650 ) set global ????tx_isolation='read-committed' show variables like 'tx_isolation' | 读已提交read-committed Set???global ????tx_isolation='read-committed' show variables like 'tx_isolation' | select * from winiis_account where username=866700?????结果 700 | select * from winiis_account where username=866700?????结果 700 | start TRANSACTION ? | start TRANSACTION ? | select * from winiis_account where username=866700?????结果 700 | update winiis_account set balance=balance-50 where username='866700'?//结果650 | select * from winiis_account where username=866700?????结果 700 | select * from winiis_account where username=866700 //结果650 | | Commit | select * from winiis_account where username=866700 ??//结果650 第二次不应该是650而是700, ?与上面的700两次查询不一致,事务A不能查询到事务B已经commit的数据,因为事务相互隔离,在同一个事务中,多次查询应该是同一个值也就是700 | select * from winiis_account where username=866700 ??//结果650 | Commit | select * from winiis_account where username=866700 ??//结果650 | select * from winiis_account where username=866700 ??//结果650 | select * from winiis_account where username=866700 ??//结果650 |
可重复读 REPEATABLE-READ set global ??tx_isolation='REPEATABLE-READ' show variables like 'tx_isolation' select * from winiis_account where username=866700?????结果 700 | 可重复读 REPEATABLE-READ set global ??tx_isolation='REPEATABLE-READ' show variables like 'tx_isolation' select * from winiis_account where username=866700?????结果 700 | start TRANSACTION | start TRANSACTION | select * from winiis_account where username=866700?????结果 700 ?事务中可重复读级别下,第一次查询的数据会被缓存到mysql中 | update winiis_account set balance=balance-50 where username='866700' | | commit | select * from winiis_account where username=866700?????结果 700 事务中可重复读级别下,第二次查询,其实查询的是上面的缓存数据,而不是最新数据,这就是可重复读。会产生幻读。 | select * from winiis_account where username=866700?????结果 650 | commit | select * from winiis_account where username=866700?????结果 650 | select * from winiis_account where username=866700??????结果 650 | select * from winiis_account where username=866700?????结果 650 |
可重复读注意点 | 可重复读注意点 | select * from winiis_account where username=866700???结果 700 | select * from winiis_account where username=866700????结果 700 | start TRANSACTION | start TRANSACTION | | update winiis_account set balance=balance-50 where username='866700'???结果650 | | Commit | select * from winiis_account where username=866700????结果 650 ?第一次查询,会查询到其他事务修改后的最新数据库记录。记住是数据库最新的记录 | select * from winiis_account where username=866700????结果 650 | | update winiis_account set balance=balance-50 where username='866700'??结果600 | select * from winiis_account where username=866700????结果 650 第二次查询是以第一次查询出来的快照版本不再是最新的记录了 | | Commit | | select * from winiis_account where username=866700??结果 600 | |
可重复读注意点 | 可重复读注意点 | select * from winiis_account where username=866700???结果 700 | select * from winiis_account where username=866700???结果 700 | start TRANSACTION | start TRANSACTION | | update winiis_account set balance=balance-50 where username='866700'???结果650 | | Commit | select * from winiis_account where username=866700????结果 650 ?第一次查询,会查询到其他事务修改后的最新数据库记录。记住是数据库最新的记录 | select * from winiis_account where username=866700??结果650 | select * from winiis_account where username=866700????结果 650 第二次查询是以第一次查询出来的快照版本不再是最新的记录了 | | update winiis_account set balance=balance-50 where username='866700'?结果600 | | select * from winiis_account where username=866700??结果600,因为自己的事务内更新后来查询,肯定能查询到自己更新后变化的数据 | | Commit | select * from winiis_account where username=866700??结果600 | select * from winiis_account where username=866700??结果600 | select * from winiis_account where username=866700??结果600 |
幻读 事务A里面读取到了事务B新增的记录(事务B有commit) | 幻读 | select * from winiis_account ??//结果69条 | select * from winiis_account ??//结果69条 | start TRANSACTION | start TRANSACTION | | insert into winiis_account(username,balance,freeze,regtime,withdrawable,version)VALUES('aaaads11a',8000,0,'',0,0) Commit | select * from winiis_account ??//结果70条 读取到了事务B ?????commit新增的数据,不符合事务隔离性 | | | winiis_account(username,balance,freeze,regtime,withdrawable,version)VALUES('aabbb',8000,0,'',0,0) | select * from winiis_account ??//结果70条 ?第二次读取到的是MVCC的快照版本70条 | | commit | select * from winiis_account ??//结果71条 |
?
?序列化,不演示,一条条地进行,项目中不会使用到
注意事项 : 更新MYSQL数据,要用以下的方式进行更新,不能使用查询后的变量去更新
推荐使用:? update winiis_account set balance=balance-50 where username='866700'? ? |
?不能使用 $balance = "selelct balance?? from winiis_account where username=866700";
update winiis_account set balance=$balance? where username='866700'? ?
|