mysql事务,依次为Read uncommitted(读未提交) 、Read committed(读已提交) 、Repeatable read(可重复读) 、Serializable (串行化)。在不同的事务隔离级别中,可能出现不同的问题,有脏读,不可重复读,幻读等等。下面分析一下他们的关系。
读未提交(Read uncommitted)
指的是在一个事务中能读取另一个事务未提交的数据。
举例:小明第一次考试60分,家长询问老师考试分数,告知是60分。在核查试卷的时候发现给小明多加了一分,修改后为59分。而小明家长收到通知是60分,实际只得了59分。
分析:实际上小明的成绩是59分,在未核对试卷(事务未提交的时候),他家长(另一个事务),获取到了未提交事务的数据(60分的成绩)。造成了读取的是错误的数据,这就是脏读。
解决方案:将事务隔离级别提高至读已提交(Read committed)。
Read committed(读已提交)
读已提交,就是读取事务已经提交的数据。
举例:小明爸爸在超市购物,在付款时让售货员查询了银行卡余额1万元,于是在售货台拿了两条中华香烟。在此时,小明妈妈有急事要用钱,就用网银把小明爸爸银行卡的一万元全部转走。当小明爸爸再次付款时,需扣款两千元,却提示余额不足。再次查询余额,发现余额为0。小明爸爸很郁闷,本来有一万元的,怎么就和刚刚查到的不一样呢?!这个现象就是不可重复读,在同一个事务里,前后查询的数据不一致。
本次事件中,小明妈妈转账快,事务也提交了,小明爸爸读取的也是事务提交的数据。但是却出现了不可重复读的问题。
解决方案:将事务隔离级别提升为:可重复读。
可重复读(Repeatable read)
可重复读,就是在同一个事务中,现将自己要读取的数据备份,将事务ID,行号,回滚数据行号指针记录。在同一个事务中,读取到的是特定的备份数据。
事例:小明爸爸经过上次事情后,聪明了。这个去超市付款时,提前将网上转账功能关闭,因此小明爸爸在付款时,其他人不能动银行卡中的余额,因此在付款前,查询余额是一万元,再挑了两条中华香烟后,自信满满的完成了付款。
本次事件中,小明爸爸在付款一个事务中,前后查询的余额是一致的,是数据库事务隔离层面的可重复读。(具体实现方式以及源码,真实数据存储结构在下篇文章中,请持续关注)
什么时候会出现幻读?
事例:小明爸爸给手机充值100元(开启事务),小明妈妈此时不知情,准备给家庭成员准备每人充值100元,于是查看下小明爸爸的话费余额10元,于是准备好银行卡,此时小明爸爸缴费到账了(事务提交)于是小明妈妈看到一条充值记录100元。
此事件中,小明妈妈的事务中,查看到了一条新增的充值记录。不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
mysql已解读可重复读级别的幻读问题了,因此,默认事务隔离级别为可重复读。
Serializable 序列化
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
在下篇文章中将介绍底层是如何实现数据库的可重复读事务隔离登记中,如何实现可重复读取数据的,在数据存储层面,深层次讲解下实现思路。