当前位置: 首页 > 科技观察

让我们一起了解ACID

时间:2023-03-18 11:11:09 科技观察

的事转载本文请联系程序员Sir公众号。随着科学技术的飞速发展,人类社会也进入了大数据时代。很多数据的取值不准确,不会对我们的生活造成很大的影响。比如我今天走的步数,手表记录的是10000步。就算记录为9500步,我也不太在意。但是有些数据必须是完全一样的,比如银行卡里的钱不能莫名其妙的丢了500元。所有的数据都必须存在于一些数据系统中,比如数据库、硬盘、云存储等。但是现在的应用越来越复杂,在访问数据系统的时候经常会出现各种各样的问题,比如:往数据库写数据的时候,出现软件或者硬件故障,导致一半的数据写入失败;应用程序突然崩溃;网络突然断开导致应用无法连接到数据库;多个客户端同时想要更新同一个值,导致后者覆盖前者。例如,小明要转100元给小华。银行应用的业务逻辑是,如果小明的账户余额大于100元,就从小明的账户中减去100元,然后在小华的账户余额中增加100元。.但是如果小明的账户刚扣了100元,银行网络就断了,后面给小华的钱就无法添加成功。这将导致一个重大问题,这在银行转帐过程中是绝对不能发生的。所以银行的应用开发需要考虑到这个异常并进行处理,比如小花在线时给账户加100元。我们可以在应用端处理各种异常,让应用更加健壮,但是需要考虑的细节很多,非常麻烦。而事务(Transaction)是一种可以简化问题的机制。1、什么是交易?事务可以将应用程序的多个读写操作组合成一个逻辑单元。理论上,一个事务中的所有读写操作都作为一个操作执行:要么整个事务的所有操作都成功,要么整个事务的所有操作都失败。不允许在事务中出现:一部分操作成功,另一部分操作失败。这简化了问题。比如上面的例子,把小明账户里的钱扣掉,小花账户里的钱加进去,就当做是一次交易。如果中间的网络断了,最多转账不成功,两边的钱还是一样的,保证不存在。金钱丢失的情况。这也方便应用重试(SafelyRetry)。你以前可能听过或用过事务,好像数据库就应该用事务。但是事务并不是天然存在的,它是为了简化访问数据库时的编程模型而创建的一个概念。使用事务可以帮助开发人员忽略一些潜在的数据问题和并发问题,因为实现事务的数据库将有助于处理此类问题。既然事务这么好,是不是所有的数据库都实现了事务,我们直接用就行了,不需要去了解事务的具体原理。其实并不是。由于事务的实现方式多种多样,层次不同,它们对应用程序性能的影响也不同。例如,实现事务隔离的一种方式是加锁。我们把一个事务涉及到的所有数据行都加锁,这样其他事务就根本无法读写我们加锁的行数据,直到事务结束才释放这些行。加锁,这样肯定能避免数据不一致。但是这样就相当于把读写数据序列化了,会极大的影响性能。银行数据非常重要。虽然这种实现速度较慢,但??保证数据安全是可以接受的。但是假设我们应用程序中的数据不是那么重要,那么我们用性能来换取数据一致性可能就不合理了。所以不是每个应用程序都需要事务。虽然交易看起来简单明了,但实际上需要考虑的细节很多,我们将一一介绍。首先介绍一下数据库中ACID的概念。2、ACID交易提供的安全保障是什么?这是对一些事务的安全保证,但是不同的数据库可能有不同的ACID实现。例如,关于隔离存在巨大的歧义。所以今天一个数据库说它满足ACID要求,但它可能和你想的ACID不一样。下面分别对这四种安全保障进行说明。2.1.原子性原子这个词很容易引起误解。大家很容易想到多线程中的原子操作。如果一个线程执行原子操作,就意味着其他线程看不到这个原子操作的中间结果。但是在ACID中,原子性与并发无关,这意味着ACID中的原子性并不意味着多个进程想要同时访问同一数据时会发生什么,而是隔离。ACID中的原子性描述的是,如果事务中途出现错误(比如网络突然断开),事务无法完成,那么事务必须回滚到事务开始前的状态。也就是说删除这个事务已经写入数据库的修改。原子性保证事务中的所有操作要么发生,要么什么都不发生。其实Abortability这个名字比atomicity更能代表这个特性,但atomicity仍然是一个更通用的名字。比如小明要转100元给小华。这笔交易包含两个操作,第一个是从小明的账户中扣除100元,第二个是向小华的账户中添加100元。原子性保证了这笔交易要么全部操作成功,要么全部操作失败,不会出现小明账户少了100元,而小花账户不变的情况。2.2.一致性(Consistency)ACID中的一致性限制了我们自定义的一些数据约束永远为真。比如上面银行转账的例子,银行定义的一个约束条件就是不管怎么转账,大家的存款总额是不变的。但一致性实际上取决于应用程序本身的定义,这意味着应用程序负责定义需要保持一致的内容。比如应用逻辑要求小明先扣100,再往小花的账户里加200。数据库不能阻止他这样做,因为这是在应用程序中定义的。数据库可能可以加一些外键约束或者唯一性约束,但是一般来说,应用负责定义哪些数据是合理的,哪些是不合理的,数据库只负责存储。有趣的一点是:原子性、隔离性和持久性都是数据库的属性,而一致性是应用程序的本质。应用程序需要基于数据库的原子性和隔离性来实现一致性。所以从某种意义上说,ACID中的C不应该属于数据库的安全保障范畴。2.3.隔离一个数据库可以被多个客户端访问。如果他们想读写数据库的不同部分,没有问题,但是如果他们想同时访问数据库的同一条记录,就可能会出现并发问题(ConcurrencyProblem),也称为竞争条件(竞争条件)。例如下面的例子:用户1和用户2都想增加数据库中counter的值。修改前是42。用户1读取42的值,在用户1改变counter的值之前,用户2也读取了42的当前值,然后用户1和用户2分别在原值上加1得到43,然后写入入数据库。最终数据库中counter的值变成了43,但实际正确的值应该是44,隔离就是为了解决这个并发问题。隔离是指并发执行的事务之前是相互隔离的,不应该相互影响。隔离是ACIDs中最复杂的,概念上有很多争议。你可能认为隔离性就是可序列化性(Serializability)。意味着数据库需要保证这些事务并发运行的最终结果需要和这些事务串行运行的结果保持一致。其实这确实是一种隔离实现,也是最高的隔离级别。但是这种实现很少被使用,因为它会对性能造成严重的影响。有些数据库甚至根本没有实现这个方案,比如Oracle。Oracle中有一个隔离级别就是“Serializable”,但是他实现的是一个比较弱的隔离级别——快照隔离(SnapshotIsolation),感觉有点像卖羊。。。各种隔离级别的区别在下篇介绍文章。2.4.持久性持久性承诺一旦事务成功完成,所有数据更改都不会回滚。即使硬盘出现故障,也能保证数据持久保存。事实上,没有任何技术可以保证数据的绝对持久化。大家只是通过一些技术来减少数据丢失,比如写入硬盘,备份等等。总结本文介绍了什么是事务以及ACID在数据库安全保证中的含义。下一篇文章将继续介绍有关事务的更多详细信息。参考文献[1]Kleppmann,Martin。设计数据密集型应用程序:可靠、可扩展和可维护系统背后的重要思想。“O'ReillyMedia,Inc.”,2017年。