概念
通俗的理解,事务是一组原子操作单元。从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么撤销不执行。事务是一个不可分割的工作逻辑单元。
ACID
事务处理几乎在每一个信息系统中都会涉及,它存在的意义是为了保证系统中所有的数据都是符合期望的,且相互关联的数据之间不会产生矛盾,即数据状态的一致性(Consistency)。
按照数据库的经典理论,要达成这个目标,需要三方面共同努力来保障:
- 原子性(Atomic):在同一项业务处理过程中,事务保证了对多个数据的修改,要么同时成功,要么同时被撤销。
- 隔离性(Isolation):在不同的业务处理过程中,事务保证了各自业务正在读、写的数据互相独立,不会彼此影响。
- 持久性(Durability):事务应当保证所有成功被提交的数据修改都能够正确地被持久化,不丢失数据。
以上四种属性即事务的“ACID”特性。
延伸问题
《凤凰架构:构建可靠的大型分布式系统》的作者周志明老师对这种说法其实不是太认同,因为这四种特性并不正交,A、I、D 是手段,C 是目的。前者是因,后者是果。
提问:ACID中的C和AID在某种层面上未必存在因果关系。譬如:表的外键,唯一,列的类型长度限制,事务的修改还可能引起触发器的修改,C需要保证事务所有的修改都满足各种条件。从这个角度看,C并不是AID的果,互相其实是正交的。
答:以前,这个观点确实是很主流的。如今,尤其是在讨论的大主题(构建可靠的分布式系统)语境下,它却一般不成立。从前认为,C和AID一样,都是数据库层面中独立的属性,如你提到的约束、触发器这些例子,就应当由数据库本身提供的C去保证。但也必须承认,C可以不通过数据库层面去实现,观察今天的应用,会发现约束、触发器的使用已经大为减少,我相信未来它们的存在感还会进一步降低,类似的一致性需求会越来越多地在应用层面去实现,而不取决于数据库。
这里引用一段《DDIA》中的类似观点供你参考:
Atomicity, isolation, and durability are properties of the database, whereas consis‐tency (in the ACID sense) is a property of the application. The application may rely on the database’s atomicity and isolation properties in order to achieve consistency, but it’s not up to the database alone.
事务场景
事务的概念虽然最初起源于数据库系统,但今天已经有所延伸,而不再局限于数据库本身了,所有需要保证数据一致性的应用场景,包括但不限于数据库、事务内存、缓存、消息队列、分布式存储,等等,都有可能会用到事务。使用“数据源”来泛指所有这些场景中提供与存储数据的逻辑设备。
上述场景所说的事务和一致性含义可能并不完全一致,说明如下:
- 当一个服务只使用一个数据源时,通过 A、I、D 来获得一致性是最经典的做法,也是相对容易的。此时,多个并发事务所读写的数据能够被数据源感知是否存在冲突,并发事务的读写在时间线上的最终顺序是由数据源来确定的,这种事务间一致性被称为“内部一致性”。
- 当一个服务使用到多个不同的数据源,甚至多个不同服务同时涉及多个不同的数据源时,问题就变得相对困难了许多。此时,并发执行甚至是先后执行的多个事务,在时间线上的顺序并不由任何一个数据源来决定,这种涉及多个数据源的事务间一致性被称为“外部一致性”。
外部一致性问题通常很难再使用 A、I、D 来解决,因为这样需要付出很大乃至不切实际的代价;但是外部一致性又是分布式系统中必然会遇到且必须要解决的问题,为此我们要转变观念,将一致性从“是或否”的二元属性转变为可以按不同强度分开讨论的多元属性,在确保代价可承受的前提下获得强度尽可能高的一致性保障,也正因如此,事务处理才从一个具体操作上的“编程问题”上升成一个需要全局权衡的“架构问题”。