如何理解数据库事务中的一致性的概念?

数据库事务,4个属性,ACID,C就是Consistency,一致性,但是教科书式的定义说明,让人有点不清楚。谁能摆事实,讲道理,解释一下何为事务一致…
关注者
478
被浏览
645,764

65 个回答

比较支持@Kai Peng 的答案,只是缺少例子说明. 而其他一些人的答案甚至有明显的错误.最近正好也在研究这方面的东西,不算是回答,就是跟大家讨论讨论.

首先,我们需要搞清楚为什么会出现事务.

[1]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).

这句话的大体含义就是,事务的产生,其实是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题.可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧?因此事务本质上是为了应用层服务的.而不是伴随着数据库系统天生就有的.

其次,说道一致性,很遗憾,这个词在不同的环境下有着不同的含义,被极大的滥用了,导致很难理解:

1. 多副本的一致性
2. 一致性hash.
3. CAP理论的一致性
4. ACID里的一致性

而这几个一致性的含义都

不是一回事!

不是一回事!

不是一回事!

所有提到最终一致性,一致读的回答,都是不对的,那是CAP里面C的含义,具体可以搜索查询Linearizability 这个词的含义,这个并不是今天的重点.


然后回到问题!!!

楼主提到了ACID,那么我们就可以简化问题单机场景下事务里一致性的含义,为什么不讨论分布式呢?因为既然一个分布式数据库提供了ACID事务保证,那么你把它看做单机又何妨呢?它是如何做到如同单机一般的,我们根本不需要关心啊.所以只考虑单机能够简化楼主的思维.

ACID里的AID都是数据库的特征,也就是依赖数据库的具体实现.而唯独这个C,实际上它依赖于应用层,也就是依赖于开发者.这里的一致性是指系统从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性.

做个比喻事务就好比一个保镖,我们提到事务就会说ACID,而我们提到保镖会说强壮,保护安全,好功夫,踏实.这里强壮,好功夫和踏实都是保镖自己的特征,而安全是属于你的,而你通过保镖的特征来保护你的安全.

但是这里必须注意,我们能够通过AID保证我们的一致性,但事务本身没办法确保.用上面保镖的例子来说,你正常被保护一定是安全的,但是你故意骗保镖离开你身边,然后你自己溜出去玩.同样,如果你在事务里故意写出违反约束的代码,比如银行系统定时每天给自己的账户打入100w,这个事务是没办法的.


这里我们举个大家都在说的财务系统的例子.

A要向B支付100元,而A的账户中只有90元,并且我们给定账户余额这一列的约束是,不能小于0.那么很明显这条事务执行会失败,因为90-100=-10,小于我们给定的约束了.

这个例子里,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证.然后我们再看个例子

A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.但是我们业务上不允许账户余额小于0.因此支付完成后我们会检查A的账户余额,发现余额小于0了,于是我们进行了事务的回滚.

这个例子里,如果事务执行成功,虽然没有破坏数据库的约束,但是破坏了我们应用层的约束.而事务的回滚保证了我们的约束,因此也可以说事务提供了一致性保证(ps:事实上,是我们应用层利用事务回滚保证了我们的约束不被破坏).最后我们再看个例子

A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.然后支付成功了.

这里,如果按照很多人的理解,事务不是保证一致性么?直观上账户余额为什么能为负呢.但这里事务执行前和执行后,我们的系统没有任何的约束被破坏.一直都是保持正确的状态.

所以,综上.你可以理解一致性就是:应用系统从一个正确的状态到另一个正确的状态.而ACID就是说事务能够通过AID来保证这个C的过程.C是目的,AID都是手段.

回答里肯定有诸多有误的地方,希望大神们能够指正~


以上.

请看下面Wikipedia中关于数据库事务一致性的定义

Consistency ensures that a transaction can only bring the database from one valid state to another, maintaining database invariants: any data written to the database must be valid according to all defined rules, including constraints, cascades,triggers, and any combination thereof. This prevents database corruption by an illegal transaction, but does not guarantee that a transaction is correct.

我对这段话的理解:

  • 数据库事务的一致性是指:保证事务只能把数据库从一个有效(正确)的状态“转移”到另一个有效(正确)的状态。那么,什么是数据库的有效(正确)的状态?满足给这个数据库pred-defined的一些规则的状态都是 valid 的。这些规则有哪些呢,比如说constraints, cascades,triggers 及它们的组合等。具体到某个表的某个字段,比如你在定义表的时候,给这个字段的类型是number类型,并且它的值不能小于0,那么你在某个 transaction 中给这个字段插入(更改)为一个 String 值或者是负值是不可以的,这不是一个“合法”的transaction,也就是说它不满足我们给数据库定义的一些规则(约束条件)。
  • “This prevents database corruption by an illegal transaction, but does not guarantee that a transaction is correct. ” 这又怎么理解呢?在数据库的角度来看,它只关心 transaction 符不符合定义好的规则,符合的就是legal的,不符合的就是illegal的。transaction 是否正确是从应用层的角度来看的,数据库并不知道你应用层的逻辑意义,它不保证应用层的transaction的正确性,这个逻辑正确性是由应用层的programmer来保证的。 这么说估计还是抽象,那么看下面我们熟知的转账的例子。
Table: Account
Columns:   Name(string), Balance(int)
约束条件:无

执行下面一个事务(A,B的初始余额均为1000,A给B转账1200)

1.  往表Account插入数据(A,1000)
2. 往表Account插入数据 (B,1000)
3. A给B转账1200,更新A的余额为-200,(A,-200)
4. B的余额增加1200,更新B的余额为2200(B,2200)

那么,数据库会认为这个 transaction 合不合法呢?也就是它满不满足我们给数据库的定义的规则呢?答案就是这个 transaction 是合法的,因为你定义表的时候没有约定 Balance 不能小于0。虽然我们从应用层的角度来看,这个transaction是不正确的,因为它不符合逻辑- balance不能小于0. 但我们数据库只关心你的 transaction 满不满足你的数据库定义的rule,不关心它具有什么业务的逻辑,这个业务逻辑是应该由应用层来理解并处理的。

修改一下上面这个例子

Table: Account
Columns:   Name(string), Balance(int)
约束条件:Balance >= 0

执行下面一个事务(A,B的初始余额均为1000,A给B转账1200)

1.  往表Account插入数据(A,1000)
2. 往表Account插入数据 (B,1000)
3. A给B转账1200,更新A的余额为-200,(A,-200)
4. B的余额增加1200,更新B的余额为2200(B,2200)

注意,这里增加了约束条件Balance > 0, 上面的这个transaction违反了规则Balance>=0,那么这个事务数据库认为它是非法的,不满足一致性的要求,所以数据库执行这个事务会失败。

最后请再认真研读一下链接 Consistency (database systems) 中的这段话。

This(Consistency)does not guarantee correctness of the transaction in all ways the application programmer might have wanted (that is the responsibility of application-level code) but merely that any programming errors cannot result in the violation of any defined database constraints.[1]