数据库事务-它们是如何工作的?

48

我试图了解更多关于数据库事务的知识,我找到了用于编写事务的ACID原则,并想到了一些问题。

ACID原则:

一个事务必须是:

  1. 原子性 - 它是一个工作单元,不依赖于前一个和下一个事务。
  2. 一致性 - 数据要么提交或回滚,没有“中间状态” ,其中某些数据已被更新而其他部分没有。
  3. 隔离性 - 没有事务看到当前事务的中间结果。
  4. 持久性 - 如果数据已经提交,则其值持久存在,即使系统在此后崩溃。

我想知道它们在底层是如何工作的,以便我可以更好地理解编写此类事务时需要考虑的因素。我猜具体细节会因可用的数据库实现而异,但某些规则将始终存在。

  1. 数据库如何处理并发事务,同时仍支持原子规则?
    • 是否有一个按顺序处理的事务队列?
    • 如何处理阻塞所有其他事务的长时间事务?
  2. 对表的更新是否在内存中完成,因此如果在提交之前发生崩溃,则不会对数据库进行任何更改?
    • 还是有一些中间表会被更新以使其在崩溃后仍然存在?
  3. 当事务正在进行时,是否防止所有读写访问所涉及的表?
    • 还是数据库允许写入,但事务将在提交时覆盖所有更改?
6个回答

16
  1. 有许多不同的方法,包括事务排队、乐观并发控制等。这实际上是一个非常复杂的问题,已经有书籍对此进行了详细阐述:

    http://www.amazon.co.uk/Databases-Transaction-Processing-Application-Oriented-Approach/dp/0201708728/ref=sr_1_3?ie=UTF8&s=books&qid=1281609705&sr=8-3

  2. 这取决于数据库中记录的日志级别。如果保持了严格的预写式日志,则在系统崩溃的情况下,可以将数据库回溯到一致的状态。

  3. 这取决于并发类型。乐观并发不涉及锁,但如果事务完成后数据库的状态已经改变,则会被放弃并重新启动。这可以加速碰撞很少的数据库。锁的级别也有不同:行、表,甚至整个数据库。

这些都是非常复杂的问题,如果您想要完全回答它们,建议购买相关书籍或参加并发系统讲座系列。


乐观并发如何处理执行副作用的事务? - user142019
3
不喜欢只推荐书籍的回答,如果你想引用一本书,可以,但请给出实际的回答,即使它更抽象。请注意不要改变原意。 - Andrew
3
通常来说,推荐一本书是一种委婉地表示:“我手头上并没有完整的了解来回答你的问题”的方式,这与 S.O. 上的回答应该要达到的效果相反。请注意,我的翻译尽力保证内容通俗易懂,但不改变原意,且不会添加任何额外信息。 - Andrew

13

关于你的定义,有一些小问题:

原子性 - 它是一个单元的工作,并且不依赖前面和后面的交易。

更正确的原子性定义不应该提及任何“前面或后面”的交易。原子性是单个事务本身的属性,即在最终倒计时中,它的所有操作要么全部持久化,要么根本不持久化。换句话说,“只允许一半的交易”不能发生。

然而,这个概念被嵌套事务、保存点和用户请求显式回滚到已取的保存点等概念所淡化。在某种意义上,这确实允许“只允许一半的交易”持久化,但这是由用户明确请求的。

一致性 - 数据要么提交,要么回滚,在更新了一些数据但未更新其他数据的“中间”情况不存在。

这个解释完全错误。一致性意味着事务处理器(在这种情况下是DBMS引擎)不能使系统(数据库)处于违反其(事务处理器)所知道的任何声明约束的状态。请参见《数据库系统导论》第16章。

隔离性 - 没有交易可以看到当前交易的中间结果。

吹毛求疵:除了当前交易,没有其他交易被允许查看中间状态(状态,而不是真正的结果)。此外,请注意,“事务处理引擎”的“隔离级别”通常定义了I属性可以被违反的程度!

持久性 - 如果数据已提交,则即使系统在崩溃后,这些值也会持久存在。

但是,嵌套事务的可能性也会模糊这种属性。即使内部事务已经提交并完成,包含事务仍然可以通过自身完全回滚来撤销该提交。


1
谢谢回复。关于嵌套事务,您有什么看法?它们是否会违反原子性和隔离性规则? - fletcher

7

实际细节可能会有所不同,具体取决于使用的数据库服务器。但是这篇文章可能会对您有所帮助:事务处理速查表


2
该链接已不再可用,但Wayback Machine保留了它的一个副本(没有图片):http://web.archive.org/web/20120827100207/http://www.cbare.org/writing/Transactions/transactions.html - Davide R.

4

在实现方面,保证每个ACID属性的努力不平衡。我可以用简化的思路总结一下:

  • 原子性最终依赖于锁定或其他原子操作来交换在事务内(在隔离性中创建)修改的数据与共享视图中的原始数据。

    数据库如何处理并发事务,同时仍支持原子规则?

    请参见隔离性

  • 一致性基于更基本的原子性隔离性属性,并且更多地扩展到应用程序层,而不是固有地属于数据库服务。

    通过对修改后的数据执行规则(当原子性隔离性已经存在时)实现这些规则相当简单。

    这可能会引发哲学上的争论。但我认为,在其非平凡情况下,可以完全通过应用逻辑或数据库层的特定于应用程序的过程来验证所有相关数据中的所有条件,从而使它们不具有数据库特定性。数据库服务必须确保的最低限度是能够读取先前写入的数据而没有错误。

    如果在提交之前崩溃,表格的更新是在内存中完成的,因此不会对数据库进行更改吗?

    请参阅隔离性

    请注意,ACID中的一致性是纯粹的逻辑、静态的,并且没有像之后由 CAP定理建议的数据传播相关的级别或等级。

  • 隔离性通过首先修改原始数据的副本(在提交更改到共享视图之前)而被普遍实现。

    在事务正在进行时,是否会阻止对受影响的表格进行所有读和写访问?

    通常情况下,如果仅在一个事务中修改了数据的副本,则其他事务不会轻易看到这些更改。但是,隔离级别可能不同。

    这是唯一允许具有一些级别和程度而不仅仅是黑白相间的ACID属性。

    最终,隔离性是所有ACID属性中最深入其实现并且可能存在权衡的属性之一。深入研究 关于这个属性是关于数据库服务保证的第一个最重要的主题(即使在CAP定理的上下文中,权衡的重点再次围绕着分布式数据上孤立视图的一致性)。

  • 耐久性实际上是一个相当的服务等级协议(SLA)

    通常会在正常事务逻辑之外协商什么样的耐久性(“写入到可腐坏的磁盘”或“冗余分布在钚动力服务器的RAM中”)。

    实现也相当简单,只需在所有可能的缓冲区刷新后确认成功的交易即可。

两个对性能至关重要的实现方面(ACID 并未明确关注):

  • 冲突检测

    应该有一种方法(有效地)检测另一个事务中同时进行的冲突更改。

    一个极端点是锁定所有不需要冲突检测的内容(没有可能的并发)。

    另一个极端点是乐观并发(至少部分如此)。然后,需要知道是否存在并发更改。这可以通过数据库中各种对象的运行计数器(版本号)或校验和来实现。然后,这与Isolation的实现密切相关。

  • 回滚过程

    这需要维护原始值及其修改副本(事务日志)的数据结构以撤消更改。同样,这与Isolation的实现方式密切相关。

一些附加的简短信息:

  • 简明说明数据库中事务实现的内容。
  • 答案避免在事务中处理非事务性资源的方法。
  • 答案如何在应用程序中实现可回滚方法。

1
一致性 - 数据要么提交,要么回滚,不存在“中间状态”,即某些内容已更新而另一些内容未更新。
我不同意Erwin Smout对一致性的看法 - 你的解释更接近实际情况。根据Ramakrishnan and Gehrke的解释,一致状态超越了系统声明的约束条件。
在将资金从一个账户划转到另一个账户的情况下,系统可能处于以下几种状态:
1. 两个账户都保持其初始余额; 2. 从一个账户余额中扣除金额,但未添加到另一个账户余额中; 3. 将金额添加到一个账户余额中,但未从另一个账户余额中扣除; 4. 两个账户都保持其最终余额。
在这四种状态中,系统的完整性约束条件都可以得到满足。但第二和第三种状态并不符合系统的合理观点 - 资金应该“存在于某个地方”。因此,这些状态不是一致的状态,而初始和最终状态是一致的。

事务并不能自动使系统保持一致性 - 它们只能让用户编写它们以达到这个目的。一个糟糕的事务可能存在漏洞,忘记将第二个账户加上信用。该事务将正常运行且完整性约束将保持。

但是,正确编写的过程会将系统从一致状态转换为一些暂时不一致的更改(例如,资金不在任何一个账户中),然后将系统恢复到一致状态。通过将这些步骤放入事务中,您可以确保系统要么达到最终一致状态(当提交时),要么返回其初始一致状态(如果回滚)。无论哪种方式,都保持了一致性。


“钱应该在某个地方。”你似乎忽略了这也是适用于系统/交易的“约束”之一。约束远远不止是键和外键。 - Erwin Smout
@ErwinSmout 我在回答中试图区分与您的回答不同之处在于,您指定了数据库知道的声明约束的一致性,而我放宽了这一点,允许未向DBMS声明的约束。我非常清楚约束的更广泛定义。 - beldaz

0
"

关于嵌套事务的判决是什么?

没有判决。嵌套事务存在,ACID属性也存在,它们被迫共存。没有绝对的规定,尤其是在ACID方面。

"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接