【MySQL】搞懂ACID原则和事务隔离级别

宜未雨而绸缪,毋临渴而掘井mysql

说说MySQL的事务

数据库事务(Database Transaction) ,是指做为单个逻辑工做单元执行的一系列操做,要么彻底地执行,要么彻底地不执行。sql

一个数据库事务一般包含对数据库进行读或写的一个操做序列。它的存在包含有如下两个目的:数据库

  • 为数据库提供一个从失败恢复正常状态的方法,同时提供了数据库即便在异常状态下仍然能保持一致性的方法。
  • 当多个应用程序并发访问数据库时,能够在这些应用程序之间提供一个隔离的方法,以防止彼此的操做相互干扰。

固然并非全部的数据库都支持事务,事务通常有四个属性:原子性、一致性、隔离性、持久性。简称:ACID原则。接下来咱们举例逐个分析:并发

  • 原子性:顾名思义原子就不可在分的,事务做为一个总体,对数据库的执行要么成功,要么失败。
  • 一致性:事务从一个一致状态转换到另外一个一致状态。
  • 隔离性:多个事务并发执行,事务之间的执行互不干扰。
  • 持久性:一旦一个事务提交,它对数据库的操做将永久保存到数据库当中。

举例:分布式

咱们用一个转帐的案例结合每一个性质分析,例如:帐户A向帐户B转帐,主要分为一下几个步骤:性能

  1. 从A帐号中把余额读出来(500)。
  2. 对A帐号作减法操做(500-100)。
  3. 把结果写回A帐号中(400)。
  4. 从B帐号中把余额读出来(500)。
  5. 对B帐号作加法操做(500+100)。
  6. 把结果写回B帐号中(600)。

原子性排序

保证6个步骤要么所有执行,要么所有不执行,若是失败了就把事务回滚到转帐的初始状态。好比:在执行到第五步的以后,帐户B忽然注销了找不到了,此时帐户A的钱也扣了,就必须事务回滚到原来各自的状态也就是A的余额500。事务

一致性get

在转帐以前A和B的帐户共有500+500=1000,而转帐成功以后,A和B的帐户是400+600=1000,就是数据的状态在执行该事务操做以后从一个状态改变到了另一个状态it

隔离性

在A给B转帐过程当中,只要事务没有提交,A和B的帐户余额不会存在变化。可是此时帐户C也在向帐户B转帐,最终两个事务提交以后帐户B的余额应该是帐户A转帐的金额加上帐户C转帐的金额。也就是说多个事务之间不会相互影响,至于C给B转帐的时候获取B的余额是已经加了A给B转帐的余额仍是没加,这个和事务的隔离级别有关系。

持久性

一旦转帐成功(事务提交),两个帐户的里面的钱就会真的发生变化(会把数据写入数据库作持久化保存)!

事务的隔离级别

  • Read-uncommitted(读未提交):最低级别,以上状况均没法保证。
  • Read-committed(读已提交):可避免脏读状况发生
  • Repeatable-read(可重复读,默认):可避免脏读、不可重复读状况的发生不能够避免虚读
  • Serializable:可避免脏读、不可重复读、虚读状况的发生。(串行,不只有read、write锁还有range lock范围锁(没有where锁全表,有where锁where范围);对一张表的全部增删改操做必须顺序执行,性能最差)
隔离级别 脏读 不可重复读 幻读
Read-uncommitted
Read-committed ×
Repeatable-read × ×
Serializable × × ×

隔离级别详解

  • Read uncommitted

做用:全部事务均可以看到其余未提交事务的执行结果

例子:

又到月底了,小明的老婆要准备给小明发生活费了,小明的老婆给小明打了500块,但该事务并无提交,而此时小明正好在查余额,发现是550块,高兴的差点蹦了起来.天有不测风云,忽然小明的老婆发现多打了50块,因而回滚事务,修改金额,而后将事务提交,最后小明空欢喜异常。

  • Read committed

做用:一个事务只能看见已经提交事务所作的改变

例子:

某个夜黑风高的夜晚,小明丰富的夜生活开始了,小明拿着工资卡去消费,pos机读取卡的信息的时候有500,而此时小红也正好在网上转帐,把小明工资卡的500元转到另外一帐户,并小明以前提交了事务,当小明扣款时,系统检查到小明的工资卡已经没有钱,扣款失败,小明十分纳闷,明明卡里有钱,为何会说余额不足,出现上述状况,即咱们所说的不可重复读,两个并发的事务,“事务1:小明消费”、“事务2:小红网上转帐”,事务1事先读取了数据,事务2紧接了更新了数据,并提交了事务,而事务1再次读取该数据时,数据已经发生了改变,当隔离级别设置为Read committed时,避免了脏读,可是可能会形成不可重复读

  • Repeatable read

    • 备注
      1. MySQL的默认隔离级别
      2. 从原理上看,可重复读是靠MVCC(多版本并发控制)保证的,该模式下,保证事务只能读取到当前事务开启以前已经提交的事务的修改以及当前事务自己对数据的修改
    • 区别
      1. 不可重复读的重点是修改,好比屡次读取一条记录发现其中某些列的值被修改(但mysql因为MVCC机制并不会有),
      2. 幻读的重点在于新增或者删除,好比屡次范围读取发现记录增多或减小了。

做用:当用户读取某一范围的数据行时,另外一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,发现和以前不同。

例子:

小红最近发现小明老是很晚回家而且常常不接电话,因而小红开始查小明当月信用卡的总消费金额,消费金额为50,而小明此时正好在收银台买单,消费1000元,即新增了一条1000元的消费记录,并提交了事务,随后小红将小明当月信用卡消费的明细打印了出来,却发现消费总额为1050元,小红很诧异,觉得出现了幻觉

  • Serializable(串行)

做用:最高级别,防止上述3种状况,事务串行执行,慎用这是最高的隔离级别,它经过强制事务排序,使之不可能相互冲突,从而避免了脏读,不可重复读,幻读。简言之,它是在每一个读的数据行上加上共享锁。在这个级别,可能致使大量的超时现象和锁竞争,并发性能最差,在分布式事务中可能会被用到。

参考文献:
http://www.hollischuang.com/archives/898

相关文章
相关标签/搜索