如果没有事务,我不敢在数据库中做任何复杂的事情。几乎总是有一个简单易用的内置命令。但是,当您开始使用其他持久数据时,您就无法获得如此简单易用的事务支持。一些例子是

  • 文件系统
  • 网络服务(我没有使用过)

即使在非持久性数据中,在发生异常后撤消工作块通常也是有用的。使用语言获得的标准数据结构都不支持事务。

我想知道的是,为什么数据库是特殊情况?

是否有任何有用的链接指向数据库之外的事务行为主题?

有帮助吗?

解决方案

我必须恭敬地不同意:事务系统并不是自动且排他的数据库引擎,恰恰相反......

我已经实现了一种与数据库事务不同的应用程序事务机制(在.NET 中)。它实际上相当简单(几个小时的工作,包括单元测试套件)。它完全用 C# 编写,不依赖于任何数据库功能或任何其他组件。但首先一些背景...

这种非数据库事务功能在 Java 平台上有多种表现形式,例如 EJB、ESB、JMS,并且通常与 BPM 相关。其中一些表现形式使用底层数据库,但并非总是如此,也不是出于必要。其他平台也有类似的表现,例如MSMQ。

大多数遗留版本控制系统不实现 ACID 事务语义。正如 ddaa 所说,CVS 不会,但 Subversion(它的后继者)会。Visual Source Safe 没有。如果您研究 Subversion,您可以找到说明这一点的比较图表。

现在的关键点是,数据库事务或类似事务并不能保证业务逻辑的安全。尽管我喜欢 Subversion,但具有讽刺意味的是,它是这一事实的一个很好的例子。

您可以虔诚地使用 Subversion 以及自动构建脚本(一个编译、测试和打包应用程序的命令),并且仍然将损坏的构建提交到源代码控制存储库。我已经多次看到了。当然,使用基于非 ACID 事务的源代码控制工具(例如 VSS)会更容易。但令许多人震惊的是,使用 Subversion 等工具可以做到这一点。

请允许我描述一下场景。您和一位同事正在开发一个应用程序,并使用 Subversion 作为源代码控制存储库。你们俩都在编码,偶尔也会提交到存储库。您进行一些更改,运行干净的构建(重新编译所有源文件),并且所有测试都通过。因此,您提交更改并回家。您的同事一直在进行自己的更改,因此他也运行了一个干净的构建,看到所有测试都通过了,并提交到存储库。但是,您的同事随后从存储库进行更新,进行了一些更改,运行了一个干净的构建,然后该构建就在他面前爆炸了!他恢复了更改,再次从存储库进行更新(只是为了确定),并发现干净的构建仍然会失败!您的同事在接下来的几个小时内对构建和源代码进行故障排除,并最终发现您在离开之前所做的更改导致了构建失败。他向你和你们共同的老板发出了一封令人讨厌的电子邮件,抱怨你破坏了构建,然后不小心回家了。你早上到达时,发现你的同事和老板正在你的办公桌前咒骂你,而其他人都在看着!因此,您快速运行一个干净的构建并向他们展示构建没有损坏(所有测试都通过了,就像昨晚一样)。

那么,这怎么可能呢?这是可能的,因为每个开发人员的工作站不是 ACID 事务的一部分;Subversion 仅保证存储库的内容。当您的同事从存储库更新时,他的工作站包含存储库内容(包括您的更改)和他自己的未提交更改的混合副本。当您的同事在他的工作站上运行干净的构建时,他正在调用不受 ACID 语义保护的业务事务。当他恢复更改并执行更新时,他的工作站随后与存储库匹配,但构建仍然损坏。为什么?因为您的工作站也是单独业务事务的一部分,与您对存储库的提交不同,该事务也不受 ACID 语义的保护。由于在运行干净构建之前您没有更新工作站以匹配存储库,因此您实际上并没有构建存储库中存在的源文件。如果您执行了此类更新,您会发现构建在您的工作站上也失败。

现在我可以阐述我的最初观点——交易具有必须仔细考虑的范围/背景。仅仅因为您有 ACID 事务并不意味着您的业务逻辑是安全的,除非 ACID 事务的范围/上下文与业务逻辑完全匹配。如果您依赖某种形式的数据库 ACID 事务,但您在业务逻辑中执行了该数据库事务未涵盖的任何操作,那么您就会出现一个间隙,可能会出现类似的灾难性错误。如果您可以强制您的业务逻辑与您的数据库事务完全匹配,那么一切都很好。如果没有,那么您可能需要单独的业务交易。根据不受保护逻辑的性质,您可能需要实现自己的事务机制。

因此,消息传递可以是事务性的,但范围仅仅是消息。对于上面的示例,Subversion 的上下文只是对存储库的单独提交。然而,业务交易是一个干净的构建,涉及的范围要大得多。这个特定问题通常通过编写干净构建脚本和干净签出脚本来解决,最好使用持续集成实现(例如,通过 CruiseControl 等)。在开发人员工作站上,它要求每个开发人员在干净的构建之前遵守纪律,执行完整的更新(甚至干净的签出)。

因此,回顾一下,每笔交易都有一个限制其保护的范围或上下文。业务事务通常包含超出我们常用的事务机制(例如数据库引擎)范围的逻辑。您可能需要弥补差额。在极少数情况下,编写自己的事务机制来执行此操作甚至可能是有意义的。

我为一家拥有 90 名员工的普通公司重写了一个关键业务系统。我觉得实行这样一个机制是有必要的,而且我觉得这种经历是轻松的、值得的、有收获的。我会再做一次,也许会更容易一些,但我总是会问为什么我不能只坚持数据库事务。

其他提示

我认为事务只能在数据库中看到的原因是,根据定义,提供事务的系统称为数据库。这听起来很循环,所以我必须详细说明。

事务支持是提供的功能 特性。通俗地说,这意味着交易是允许 1.将许多谨慎的操作捆绑到一个包中,该包要么整体成功,要么整体失败 2.隐藏并发用户未提交的更改,以便 3.并发用户始终拥有系统的“一致”视图。

文件系统 传统上提供一些锁定机制,但这与提供事务不同。然而,所有文件系统都具有一些原子属性。例如,如果您有目录 /a//b/, ,并且您同时尝试执行 mv /a /b/amv /b /a/b, ,在不损害完整性的情况下,只有其中一项操作会成功。然而,文件系统通常缺乏将多个操作捆绑到一个独立的原子包中的能力。

一个答案 提到颠覆。所有健全的版本控制系统都有事务。当提交到多个文件时,系统要么完全应用提交,要么完全拒绝它(CVS 除外,我不认为它是理智的)。拒绝的原因总是同时发生的变化。版本控制系统实现者非常有意识地维护数据库。

其他 答案提到消息传递系统是事务性的。我没有阅读链接的材料,但答案本身只提到了消息的原子传递。那不是交易。

我从来没有听说过 克洛尤尔布莱恩·C. 这里提到过。在我看来,这确实是数据库上下文之外事务的实现。这里的重点是并发控制,而不是维护持久数据的一致性。

因此,除了 Clojure 之外,似乎任何需要事务的系统要么使用底层数据库,要么将自身变成数据库。

现代文件系统确实有事务。它们对最终用户来说是透明的。

NTFS、XFS、JFS、EXT3 和 ReiserFS 都可以,仅举几例。

这只是文件系统的内部。许多操作系统还支持具有独占(写)锁和共享(读)锁的文件锁定(例如,请参阅 *NIX 世界中的集群(2))。

编辑:如果你想一想,文件系统没有像现代数据库那样的隔离级别,因为一旦你读完一个文件,如果你没有锁定它,传统上你会关闭它。然后当您想写入时重新打开它。

克洛尤尔 用途 软件事务内存, ,它使用事务可以轻松安全地编写多线程程序,而无需手动锁定。Clojure 具有不可变的数据结构和对它们的可变引用,并且需要事务来更改引用。

消息传递系统是事务资源管理器的另一个例子。

也就是说,您可以确保消息使用者成功处理来自队列的消息。如果处理失败,则消息将留在队列中。

此外,消息传递系统可以参与与另一个资源管理器的分布式事务。

更多信息请访问

Subversion 提交是事务性的:它们是真正的原子性,因此中断的提交不会使存储库处于不一致的状态。

我遇到了需要将文件系统和数据库视为一个事务单元的情况。

就我而言,我只需要将一组文件下载到文件系统中。我通过每次创建随机目录,将数据放在那里,并将目录名称存储在数据库表中来做到这一点。因此,我的所有数据库工作以及数据库表中的目录名称(= 文件系统工作)都可以在一个数据库事务中完成。

http://www.databasesandlife.com/atomic-operations-over-filesystem-and-database/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top