在只有选择的事务中提交和回滚之间有区别吗?

Posted

技术标签:

【中文标题】在只有选择的事务中提交和回滚之间有区别吗?【英文标题】:Is there a difference between commit and rollback in a transaction only having selects? 【发布时间】:2010-09-16 22:05:59 【问题描述】:

我们在我公司使用的内部应用程序框架使得有必要将每个 SQL 查询放入事务中,即使我知道没有任何命令会在数据库中进行更改。在会话结束时,在关闭连接之前,我提交事务以正确关闭它。我想知道如果我回滚它是否有什么特别的区别,尤其是在速度方面。

请注意,我使用的是 Oracle,但我猜其他数据库也有类似的行为。另外,我对开始交易的要求无能为力,那部分代码库不在我的掌控之中。

【问题讨论】:

【参考方案1】:

数据库通常会保留前映像日志(事务前的状态)或后映像日志(事务完成时的状态。)如果保留前映像,则必须恢复在回滚。如果它保留一个残像,则必须在提交时替换数据。

Oracle 有日志和回滚空间。事务日志累积块,稍后由 DB 写入者写入。由于这些是异步的,几乎没有任何与数据库写入器相关的内容对您的事务有任何影响(如果队列已满,那么您可能需要等待。)

即使对于仅查询事务,我也愿意打赌在 Oracle 的回滚区域中存在一些事务记录保存。我怀疑回滚需要 Oracle 在确定没有任何实际回滚之前需要做一些工作。我认为这与您的交易同步。在回滚完成之前,您不能真正释放任何锁。 [是的,我知道您没有在事务中使用任何东西,但锁定问题是为什么我认为必须完全释放回滚,然后才能释放所有锁,然后您的回滚就完成了。]

另一方面,提交或多或少是预期的结果,我怀疑丢弃回滚区域可能会稍微快一些。您没有创建任何事务条目,因此 db writer 永远不会醒来检查并发现无事可做。

我还希望,虽然提交可能会更快,但差异会很小。如此微小,以至于您甚至可能无法在并排比较中测量它们。

【讨论】:

我根本不认为这是对 oracle 工作方式的描述。这听起来像是已应用于 Oracle 的通用描述。猜测甲骨文的工作方式不太可能有帮助。 Oracle 将日志称为“重做日志文件”。它将回滚段称为“撤消表空间”。你知道哪个更快吗?提交还是回滚? 如果没有工作要做,那么几乎可以肯定没有区别。 Oracle 针对快速提交进行了优化——它只需要将提交记录写入重做日志缓冲区并刷新缓冲区(10g+ 中的异步提交除外)。回滚需要更多的工作。 asktom.oracle.com/pls/asktom/…,Tom Kyte 表示如果没有事务,数据库实际上不会做任何提交工作。您可能可以通过非常快速地进行数百次提交并检查日志文件同步事件的计数来检查这一点。【参考方案2】:

我同意之前的答案,即在这种情况下 COMMIT 和 ROLLBACK 之间没有区别。确定没有任何内容可提交所需的 CPU 时间与确定没有任何内容可回滚所需的 CPU 时间之间的差异可能可以忽略不计。但是,如果差异可以忽略不计,我们可以放心地忘记它。

但是,值得指出的是,在单个事务的上下文中执行大量查询的会话与在一系列事务的上下文中执行相同查询的会话之间存在差异。

如果客户端启动事务、执行查询、执行 COMMIT 或 ROLLBACK,然后启动第二个事务并执行第二个查询,则无法保证第二个查询将观察到与第一个查询相同的数据库状态。有时,维护数据的单一一致视图至关重要。有时,获取数据的最新视图至关重要。这取决于你在做什么。

我知道,我知道,OP 没有问这个问题。但是有些读者可能会在他们的脑海中问这个问题。

【讨论】:

【参考方案3】:

一般来说,COMMIT 比 ROLLBACK 快得多,但在你什么都不做的情况下,它们实际上是相同的。

【讨论】:

【参考方案4】:

文档指出:

Oracle 建议您在与 Oracle 数据库断开连接之前,使用 COMMIT 或 ROLLBACK 语句显式结束应用程序中的每个事务,包括最后一个事务。如果你没有显式地提交事务并且程序异常终止,那么最后一个未提交的事务会自动回滚。大多数 Oracle 实用程序和工具的正常退出会导致提交当前事务。 Oracle 预编译器程序的正常退出不会提交事务,而是依赖 Oracle 数据库回滚当前事务。

http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_4010.htm#SQLRF01110

如果你想选择做一个或另一个,那么你还不如做一个和什么都不做一样的事情,然后就去做。

【讨论】:

这实际上取决于客户端。 sqlplus,它是一个隐式提交。其他的可能不是。如果网络连接被切断(例如,客户端只是“离开”),那么它就是一个回滚。 我不确定它是否依赖于应用程序,我可能应该说“优雅断开连接”,但文档说“在应用程序正常终止或.. 。”download.oracle.com/docs/cd/B28359_01/server.111/b28318/… 实际上,我找到了更好的参考并编辑了我的帖子。谢谢。【参考方案5】:

好吧,我们必须考虑 SELECT 在 Oracle 中返回的内容。有两种模式。默认情况下,SELECT 返回数据,因为数据在 SELECT 语句开始执行的那一刻开始执行(这是 READ COMMITTED 隔离模式的默认行为,默认事务模式)。因此,如果在发出 SELECT 之后执行了 UPDATE/INSERT,则结果集中将不可见。

如果您需要比较两个结果集(例如总账应用程序的债务方和贷方方),这可能会出现问题。为此,我们有第二种模式。在该模式下,SELECT 返回当前事务开始时的数据(READ ONLY 和 SERIALIZABLE 隔离级别的默认行为)。

因此,至少有时需要在事务中执行 SELECT。

【讨论】:

【参考方案6】:

由于您没有执行任何 DML,我怀疑 Oracle 中的 COMMIT 和 ROLLBACK 之间没有区别。无论哪种方式,都无事可做。

【讨论】:

【参考方案7】:

我认为 Commit 会更有效率;因为通常您希望提交大多数数据库事务;所以你会认为数据库针对这种情况进行了优化(而不是试图更有效地进行回滚)。

【讨论】:

以上是关于在只有选择的事务中提交和回滚之间有区别吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在休眠中处理多个会话事务提交和回滚?

什么是事务事务中的提交和回滚是什么意思

如何使用 codeigniter 中的事务进行基于数据更改的提交和回滚?

mysql事务的提交和回滚

Laravel 4 DB 事务未提交和回滚

系统故障时自动恢复进程将使用事务日志前滚所有已提交的事务,并回滚任何未完成的事务。啥是前滚和回滚