目录
- 事务简介
- 事物的定义
- 事务的目的
- 事务的状态
- 事务的ACID属性
- ACID简介
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
- 总结
- 参考文献
版权声明:本文为Heriam博主原创文章遵循CC 4.0 BY-SA 版权协议转载请附上原文出处链接和本声明
原文链接:https://jiang-hao.com/articles/2019/backend-transactions-acid.html
事务简介
事物的定义
事务(Transaction)是由一系列对系统中数据进行访问或更新的操作所组成的一个程序执行逻辑单元(Unit)在计算机术语中事务通常就是指数据库事务
在数据库管理系统(DBMS)中事务是数据库恢复和并发控制的基本单位它是一个操作序列这些操作要么都执行要么都不执行它是一个不可分割的工作单位
例如银行转帐工作:从源帐号扣款并使目标帐号增款这两个操作必须要么全部执行要么都不执行否则就会出现该笔金额平白消失或出现的情况所以应该把他们看成一个事务
在现代数据库中事务还可以实现其他一些事情例如确保你不能访问别人写了一半的数据但是基本思想是相同的——事务是用来确保无论发生什么情况你使用的数据都将处于一个合理的状态:
transactions are there to ensure, that no matter what happens, the data you work with will be in a sensible state.
它保证在任何情况下都不会出现在转账后从一个帐户中扣除了资金而未将其存入另一个帐户的情况
事务的目的
数据库事务通常包含了一个序列的对数据库的读/写操作包含有以下两个目的:
- 为数据库操作序列提供了一个从失败中恢复到正常状态的方法同时提供了数据库即使在异常状态下仍能保持一致性的方法
- 当多个应用程序在并发访问数据库时可以在这些应用程序之间提供一个隔离方法以防止彼此的操作互相干扰
当事务被提交给了DBMS则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中如果事务中有的操作没有成功完成则事务中的所有操作都需要回滚回到事务执行前的状态同时该事务对数据库或者其他事务的执行无影响所有的事务都好像在独立的运行
Martin Kleppmann在他的《Designing Data-Intensive Applications》一书中有提到:
Transactions are not a law of nature; they were created with a purpose, namely to simplify the programming model for applications accessing a database. By using transactions, the application is free to ignore certain potential error scenarios and concurrency issues, because the database takes care of them instead (we call these safety guarantees).
在现实情况下失败的风险很高在一个数据库事务的执行过程中有可能会遇上事务操作失败、数据库系统或操作系统出错甚至是存储介质出错等情况而上述Martin的话说明了事务的存在就是为了能够简化我们的编程模型不需要我们去考虑各种各样的潜在错误和并发问题 我们在实际使用事务时不需要考虑数据库宕机网络异常并发修改等问题整个事务要么提交要么回滚非常方便所以本质上来说事务的出现了是为了应用层服务的而不是数据库系统本身的需要
事务的状态
因为事务具有原子性所以从外部看的话事务就是密不可分的一个整体事务的状态也只有三种:Active、Commited 和 Failed事务要不就在执行中要不然就是成功或者失败的状态
进一步放大看事物内部还有部分提交这个中间状态其对外是不可见的
所以具体来说事务有以下几种可能的状态:
- Active:事务的初始状态表示事务正在执行
- Partially Committed:在最后一条语句执行之后
- Failed:发现事务无法正常执行之后
- Aborted:事务被回滚并且数据库恢复到了事务进行之前的状态之后
- Committed:成功执行整个事务
我们也可以看到事务在执行之后只会以Aborted或者Committed状态作为结束
事务的ACID属性
ACID简介
为了保持数据库的一致性在事务处理之前和之后都遵循某些属性也就是大家耳熟能详的ACID属性:
- 原子性(Atomicity):即不可分割性事务中的操作要么全不做要么全做
- 一致性(Consistency):一个事务在执行前后数据库都必须处于正确的状态满足完整性约束
- 隔离性(Isolation):多个事务并发执行时一个事务的执行不应影响其他事务的执行
- 持久性(Durability):事务处理完成后对数据的修改就是永久的即便系统故障也不会丢失
并非任意的对数据库的操作序列都是数据库事务ACID属性是一系列操作组成事务的必要条件总体而言ACID属性提供了一种机制使每个事务都”作为一个单元完成一组操作产生一致结果事务彼此隔离更新永久生效“从而来确保数据库的正确性和一致性
原子性(Atomicity)
原子性也被称为“全有或全无规则”它非常好理解即整个事务要么完整发生要么根本不发生不会部分发生它涉及以下两个操作:
- 中止:如果事务中止则看不到对数据库所做的更改
- 提交:如果事务提交则所做的更改可见
拿之前转账的例子来说用户A给用户B转账至少要包含两个操作用户A钱数减少用户B钱数增加增加和减少的操作要么全部成功要么全部失败是一个原子操作如下图如果事务在T1 完成之后但在T2完成之前失败将导致数据库状态不正确
一致性(Consistency)
一致性是指一个事务必须使数据库从一个一致性状态变换到另一个一致性状态(执行成功)或回滚到原始的一致性状态(执行失败)这意味着必须维护完整性约束以使在事务之前和之后数据库保持一致性和正确性
参考上面的示例假设用户A和用户B两者的钱加起来一共是700那么不管A和B之间如何转账转几次账这一约束都得成立即事务结束后两个用户的钱相加起来还得是700这就是事务的一致性
如果转账过程中仅完成A扣款或B增款两个操作中的一个即未保证原子性那么结果数据如上述完整性约束也就无法得到维护一致性也就被打破可以看出事务的一致性和原子性是密切相关的原子性的破坏可能导致数据库的不一致
但数据的一致性问题并不都和原子性有关比如转账的过程中用户A扣款了100而用户B只收款了50那么该过程可以符合原子性但是数据的一致性就出现了问题
一致性既是事务的属性也是事务的目的也正如本文开篇所提到的“事务是用来确保无论发生什么情况你使用的数据都将处于一个合理的状态“这里所说的合理/正确也就是指满足完整性约束
总的来说一致性是事务ACID四大特性中最重要的属性而原子性、隔离性和持久性都是作为保障一致性的手段事务作为这些性质的载体实现了这种由ACID保障C的机制
ACID和CAP中C(一致性)的区别
请注意我们一直在讨论的一致性即ACID中的C是指单一实体内部的正确状态在时间维度上的一致性进一步说是通过维护数据的完整性约束来保持数据库在时间上(比如事务前后)保持一致的正确状态因为是描述单一实体的内部状态故又称“内部一致性”
而CAP原则中的一致性是指在分布式系统中空间维度上某一特定时刻多个实体中不同数据备份之间值的一致性又称“外部一致性”具体我们会在另文CAP原则相关内容中做详细介绍
隔离性(Isolation)
隔离性是指并发执行的各个事务之间不能互相干扰即一个事务内部的操作及使用的数据对并发的其他事务是隔离的此属性确保并发执行一系列事务的效果等同于以某种顺序串行地执行它们也就是要达到这么一种效果:对于任意两个并发的事务T1和T2在事务T1看来T2要么在T1开始之前就已经结束要么在T1结束之后才开始这样每个事务都感觉不到有其他事务在并发地执行这要求两件事:
- 在一个事务执行过程中数据的中间的(可能不一致)状态不应该被暴露给所有的其他事务
- 两个并发的事务应该不能操作同一项数据数据库管理系统通常使用锁来实现这个特征
还是拿转账来说在A向B转账的整个过程中只要事务还没有提交(commit)查询A账户和B账户的时候两个账户里面的钱的数量都不会有变化如果在A给B转账的同时有另外一个事务执行了C给B转账的操作那么当两个事务都结束的时候B账户里面的钱必定是A转给B的钱加上C转给B的钱再加上自己原有的钱
如此隔离性防止了多个事务并发执行时由于交叉执行而导致数据的不一致事务隔离分为不同级别包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)以上4个级别的隔离性依次增强分别解决不同的问题事务隔离级别越高就越能保证数据的完整性和一致性但同时对并发性能的影响也越大
持久性(Durability)
事务的持久性又称为永久性(Permanency)是指一个事务一旦提交对数据库中对应数据的状态变更就应该是永久性的即使发生系统崩溃或机器宕机等故障只要数据库能够重新启动那么一定能够根据事务日志对未持久化的数据重新进行操作将其恢复到事务成功结束的状态持久性意味着在事务完成以后该事务所对数据库所作的更改便持久的保存在数据库之中并不会因为系统故障而被回滚(完成的事务是系统永久的部分对系统的影响是永久性的)
许多数据库通过引入预写式日志(Write-ahead logging缩写 WAL)机制来保证事务持久性和数据完整性同时又很大程度上避免了基于事务直接刷新数据的频繁IO对性能的影响
在使用WAL的系统中所有的修改都先被写入到日志中然后再被应用到系统状态中假设一个程序在执行某些操作的过程中机器掉电了在重新启动时程序可能需要知道当时执行的操作是成功了还是部分成功或者是失败了如果使用了WAL程序就可以检查log文件并对突然掉电时计划执行的操作内容跟实际上执行的操作内容进行比较在这个比较的基础上程序就可以决定是撤销已做的操作还是继续完成已做的操作或者是保持原样
总结
事务(Transaction)是由一系列对系统中数据进行访问或更新的操作所组成的一个程序执行逻辑单元(Unit)在事务的ACID特性中C即一致性是事务的根本追求而对数据一致性的破坏主要来自两个方面:
- 事务的并发执行
- 事务故障或系统故障
数据库系统是通过并发控制技术和日志恢复技术来避免这种情况发生的
并发控制技术保证了事务的隔离性使数据库的一致性状态不会因为并发执行的操作被破坏
日志恢复技术保证了事务的原子性使一致性状态不会因事务或系统故障被破坏同时使已提交的对数据库的修改不会因系统崩溃而丢失保证了事务的持久性
我们将另文对以上两种技术进行详细介绍
参考文献
What is a database transaction? (2019). Retrieved November 5, 2019, from Stack Overflow website: https://stackoverflow.com/questions/974596/what-is-a-database-transaction
Communcations and Information Processing: First International Conference, ICCIP 2012, Aveiro, Portugal, March 7-11, 2012, Proceedings, 第 2 部分
Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems, 第25节
ACID Properties in DBMS - GeeksforGeeks. (2016, August 7). Retrieved November 5, 2019, from GeeksforGeeks website: https://www.geeksforgeeks.org/acid-properties-in-dbms/
维基百科. (2011, July 25). 预写式日志. Retrieved November 5, 2019, from Wikipedia.org website: https://zh.wikipedia.org/wiki/%E9%A2%84%E5%86%99%E5%BC%8F%E6%97%A5%E5%BF%97
数据库事务的概念及其实现原理 - takumiCX - 博客园. (2018). Retrieved November 5, 2019, from Cnblogs.com website: https://www.cnblogs.com/takumicx/p/9998844.html
浅入深出MySQL中事务的实现. (2017, August 20). Retrieved November 5, 2019, from 面向信仰编程 website: https:/https://p.download-x.com/draveness.me/mysql-transaction
相关文章
猜您喜欢
- 01-30es6 语法
- 01-30Redhat下如何查看nvidia显卡的工作状况
- 01-30手势识别控制pygame精灵
- 01-30c#实现ofd文件转图片功能 (附执行程序)
- 01-30一千行 MySQL 学习笔记
- 01-30痞子衡嵌入式:语音处理工具pzh-speech诞生记(4)- 音频录播实现(PyAudio)