MySQL ACID

ACID

数据库事务有ACID四个属性,分别是原子性、一致性、隔离性、持久性。

原子性(Atomicity)

整个事务最终只能是要么成功要么失败,不能存在中间状态,如果发生错误了就需要回滚回去,就像这个事务从来没有执行过一样。


一致性(Consistency)

指系统要处于一个一致的状态,不能因为并发事务的多少影响到系统的一致性,举个典型的例子就是转帐的情况,假设有ABC三个帐号各有100元,
那么不管这三个帐号之间怎么转账,整个系统总的额度是300元这一点是应该是不变的。其实ACID里的一致性更多的是应用程序需要考虑的问题,
和分布式系统里的CAP里的一致性完全不是一个概念。


隔离性(Isolation)

本质上是解决并发执行的事务如何保证数据库状态是正确的,抽象描述叫可串行化,就是并发的事务在执行的时候效果要求达到看起来像是一个个事务串行执行的效果。
有冲突的事务之间的隔离性如果保证不了会引起前面的一致性(consistency)也无法满足。


持久性(Durability)

在事务完成以后所有的修改可以持久的保存在数据库中,一般会采用WAL的方式,会把操作提前记录到日志中来保证即使操作还没有刷到磁盘就宕机的情况下有日志可以恢复。

MySQL无法提供严格的分布式事务语义的支持

如果客户端发送的SQL只涉及到一个节点,那自然是可以保证事务的,但是如果客户端发送的SQL涉及到两个及以上节点的SQL,那就无法保证事务语义了。原因主要是两个:

  • 原子性无法保证,在一个节点commit成功以后,在另外的节点commit失败了,这个事务就处在一个中间状态,此时原子性被打破。

  • 隔离性,这个事务的一部分提交了,另一部分未提交,此时该事务正常是不该被读取到的,但是提交成功的部分会被其他事务读到,此时就无法保证隔离性了。

另外就算是涉及多个节点的操作都是成功的,理论上来说也是无法保证隔离性的。因为假设A事务的一个节点先commit成功,其他的节点后commit成功,而此时B事务在读取的
时候可能会读取到了A事务最早commit成功的那部分内容,却没有读到后来commit成功的内容,此时依然无法保证隔离性。

更本质一点的原因是MySQL的事务都是每个实例维护自身的事务ID,而基于MySQL集群的分布式方案没有一个全局的事务ID来标识每个MySQL实例上的事务以及全局事务的元信息
的管理,所以无法做到严格的分布式事务语义。

但实际上绝大多数业务对这个需求未必那么强烈,因为绝大多数的业务逻辑都是可以拆分的,拆成一个个只落在一个分库里的操作在绝大多数场景下是完全可行的,而且拆分完以后
也会更可控,所以这个问题在我们支撑业务的过程中也不是一个特别大的问题。

隔离级别


READ UNCOMMITTED

事务中的修改,即使没有提交,对其他事务也都是可见的。从性能来说,READ UNCOMMITTED不会比其他的级别好太多,实际应用中很少使用。

事务可以读取未提交的数据,称为脏读(Dirty Read)。


READ COMMITTED

大多数数据库默认的级别,这个级别只是满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。

即一个事务从开始直到提交前,所做的任何修改对其他事务是不可见的。

这个级别也称为不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果。


REPEATABLE READ

该级别解决了脏读问题,保证了在同一个事务中多次读取同样的记录的结果是一致的。

但是该级别在理论上,还是无法解决另一个问题——幻读(Phantom Read)。

Phantom Read:当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,此时如果之前的事务再次读取该范围的
记录时,会产生幻行(Phantom Row)

注:InnoDB和XtraDB通过多版本并发控制(MVCC,Mutlversion Concurrency Control)解决了幻读问题。

关于账户转账出问题的参考案例:http://www.importnew.com/28657.html


SERIALIZABLE

最高级别的隔离,通过强制事务串行执行,避免了前面提到的幻读(Phantom Read)问题。

该级别会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。

总结

隔离级别 Dirty Read Nonrepeatable Read Phantom Read Locked Read
READ UNCOMMITTED yes yes yes no
READ COMMITTED no yes yes no
REPEATABLE READ no no yes no
SERIALIZABLE no no no yes