在学习数据库时一定都听说过事务的四要素:ACID,但是大多数人对事务四要素的理解一直停留在课本概念层面并没有仔细的琢磨,当我们在实际工作中遇到问题时经常要去回顾这四要素的概念,甚至很多人说不清事务四要素具体是什么。

相信大家在实际工作中最常遇到的问题就是死锁(dead lock),说到死锁就不得不说先说事务,我们都知道死锁是并发事务时经常会遇到的问题,当然死锁的场景也非常多并且与数据库事务隔离级别有着很大的关系,这些不懂都没有关系,今天我们就花一分钟来理解消化事务的四要素。

事务四要素:ACID

说到事务的四个要素,最容易理解的就是原子性,但是其他三个要素:一致性、隔离性、持久性也是非常重要,恰恰也是经常被人忽视的。

原子性(Atomicity)

原子性非常容易被人理解,直白点说就是一个事务中的所有操作(CRUD)就像是一个原子操作一样不可分割开来,要么全部成功,要么全部失败,不允许部分成功部分失败。

举个例子:

  1. 往篮子里放入一个苹果
  2. 随后从篮子里拿出一个梨
    这两个动作要么都成功,要么都失败,不存在只往篮子里放苹果而没拿梨,也不存在只从篮子里拿梨而没有放苹果。

原子性的侧重点在于多个动作必须同时成功或者同时失败。

一致性(Consistency)

网上争议最多的就是对一致性的理解,公说公有理婆说婆有理,我觉得还是仁者见仁智者见智。

说法一:事务开始和结束后,数据库的完整性约束没有被破坏,如外键约束。
说法二:一个事务单元需要提交之后才会被其他事务可见。

网上有很多用张三给李四转账的例子来说明一致性,但是看起来感觉跟原子性的概念雷同,这也是经常会有人傻傻分不清一致性和原子性的区别。

说法三:一致性和原子性的区别在于两者的侧重点不同,原子性关注的是状态,要么全部成功,要么全部失败,不存在部分成功的状态。而一致性关注的是数据的可见性,一个事务的中间状态的数据对外部不可见,只有最初状态和最终状态的数据对外可见。

其实这个说法是对的,但是理解起来不通俗易懂甚至有些模糊,很难让人很通俗易懂的明白其中的区别。

而且看到上面区别解释后又会有人提出挑战说,当事务的隔离级别是Read Uncommitted(读未提交)时,可以把事务的中间状态数据对其他事务可见,这个不就是违背了一致性么?

其实事务的隔离级别就是在事务的四要素和性能上面做平衡,有时候为了提高性能,会适度的破坏一致性原则。

这篇文章是我见过对一致性理解最靠谱的。

说回到主题一致性的理解上,我对一致性的理解是这样的,一致性关注的点是数据的操作结果是否与用户业务预期一致,这里有两点需要注意。

  1. 一致性关注的是结果状态,什么是结果状态?它是一个要达到的预期效果并非是一个保证手段。而数据库的唯一建、外键、主键等这些约束建和AID原则:原子性(A)、隔离性(I)、持久性(D)以及提交、回滚等动作是保证结果能达到与预期效果一致的手段。
  2. 一致性它是由用户的业务决定的并非数据库决定的,网上很多的例子解释一致性都是狭义的理解,为什么这样说的?比如说账户扣钱,如果业务约束账户不允许为负数,那当扣成负数的时候就会通过回滚来保持一致性,如果业务约束账户允许为负数,那当扣成负数也可以正常提交来保持一致性,那这两个最终的状态是完全不一样的,但都是满足用户预先设置好的约束规则,所以一致性是由用户来决定的,从结果来看只要符合业务预期约束就是满足一致性的。

隔离性(Isolation)

并发事务之间不会互相影响,就像串行执行一样,也就是说并发事务之间都是互相隔离的,你不影响我,我也不影响你。
隔离性侧重点是并发事务之间的影响,说到并发事务就要提到数据库的隔离级别,有的时候会通过调整数据库的隔离级别来适度的破坏一致性和隔离性,从而提高数据库处理性能。

ps. 画外音,隔离性是我们需要重点关注的,因为不同的隔离级别,可能对应的加锁过程不一样,而正是因为引入了各种各样的隔离级别,才让锁问题变得格外复杂。解决和分析死锁问题,重点就是要搞清楚数据库的隔离级别。那么隔离级别是个什么东西呢?我们会在后面出单独的文章来重点说明。

持久性(Durability)

持久性就非常好理解了,事务提交后即持久化到磁盘不会丢失。
持久性侧重的是数据不丢失,这个跟网上讨论最多的 (“丢失更新”“提交覆盖”“Read-Modify-Write问题”)很容易混淆,看起来效果都是没有存入正确的数据,看起来好像数据丢失了一样。
实际上两者区别很大的,前者是说数据存到物理磁盘不会丢失,而后者则说的是并发事务中的相互影响导致最终的数据结果不同。

总结

这一章我们对事务的ACID进行了快速的理解,这里容易混淆的有原子性和一致性。

  1. 原子性的侧重点在于操作完整不可分隔,往篮子里放入一个苹果随后从篮子里拿出一个梨,不存在只往篮子里放入苹果没有拿梨,也不存在只从篮子里拿梨没有放入苹果。
  2. 一致性的侧重点在于结果状态是否与用户的预期效果一致。
  3. 隔离性的侧重点在于并发事务之间互不影响,切记不是你中有我我中有你。
  4. 持久性的侧重点在于数据落盘不丢,切记不是并发事务导致的最终数据结果丢失。

下一章我们会从事务的隔离级别来进行快速学习和掌握,隔离级别会分两章来进行,先让大家搞清楚我们最常挂在嘴边的也是面试最常问道的:脏读、幻读、不可重复度、可重复度、丢失更新的定义和区别,我会尽量用通俗易懂的方式来让大家明白。

附录

这里从网上找了一些关于事务的文章,不用太纠结对错,仁者见仁,智者见智,有句俗话是这样说的:不要太认真,认真你就输了,哈哈。。。。

  1. https://www.aneasystone.com/archives/2017/10/solving-dead-locks-one.html
  2. https://www.cnblogs.com/autointerface/p/11959711.html
  3. http://novoland.github.io/%E6%95%B0%E6%8D%AE%E5%BA%93/2014/07/26/MySQL%E6%80%BB%E7%BB%93.html

ps. 文章中有哪些错误的地方欢迎指正。

好像文章有点长阅读起来超过了一分钟,看来功力还不够没有压缩到一分钟,希望能帮助到需要的人。

Love and peace!