应该在存储过程之外还是在内部指定事务?

Posted

技术标签:

【中文标题】应该在存储过程之外还是在内部指定事务?【英文标题】:Should transactions be specified outside a stored procedure or inside? 【发布时间】:2010-10-11 17:53:55 【问题描述】:

我们可以在事务中包装对存储过程的调用并指定隔离级别。

或者我们可以把事务放在存储过程里面指定一个隔离级别。

哪个更好?

【问题讨论】:

【参考方案1】:

存储过程里面是我认为最合适的位置。

良好的事务设计的基本规则之一是尽可能缩短事务的生命周期,因此提交应该在事务逻辑完成后立即发生。在存储过程之外控制事务将导致不必要地延长事务的生命周期。

您还应该考虑在过程中定义事务也会使您的代码更加清晰。否则,如果另一个编码人员需要修改给定的存储过程,他们将不得不依赖调用者确实将过程包装在事务中这一事实。在过程中包含事务明确定义了您的事务处理。

【讨论】:

对于谁决定得分 -1,提供你的理由是礼貌的。【参考方案2】:

您应该采用一致的方法。请注意,在存储过程中回滚事务将回滚任何嵌套事务范围,包括任何外部范围。

我建议您不要在程序之外进行交易。这样,您就可以完全控制。

【讨论】:

这是不正确的。如果你嵌套了多个 BEGIN TRANSACTION 开始并且最深的一个回滚,它们都回滚...... @Dems:您在这方面是部分正确的,只有当您不使用带有 transaction_name 参数的事务时才会出现这种情况。这就是为什么应明确定义事务以实现完全控制的原​​因。参考msdn.microsoft.com/en-us/library/ms189336.aspx。 Dems:出于某种原因,我写的是“接受”而不是“回滚”,这没有什么意义。感谢您指出:-)【参考方案3】:

仅供参考,Oracle 不支持嵌套事务,如果您在外部级别开始事务,然后调用一系列存储过程,则任何发出提交的存储过程都将提交整个事务,而不仅仅是它煽动的交易。因此,当从 C# 等语言调用时,您必须在存储过程之外管理事务

只是想你可能会感兴趣,作为比较。

【讨论】:

它确实支持autonomous_transactions,它允许您在当前交易之外开始新的交易。不过,它们几乎总是一个坏主意。它还支持保存点。它允许部分回滚,虽然它不是我用过的东西。【参考方案4】:

在您的数据库 API 的外层,或者至少在外层。

如果您在每个存储过程中提交,那么您不妨打开自动提交,想象以下存储过程

create_user_with_email_address
  calls -> create_user
  calls -> create_email_address

如果您在 create_user/create_email_address 中提交,则 create_user_with_email_address 不能再进行事务处理,如果 create_email_address 失败,则 create_user 已提交,并且您已损坏数据。

根据需要将事务放在尽可能高的位置以将所有内容保留在其中。

【讨论】:

我不认为这是真的,如果外部事务回滚它也会回滚任何嵌套事务。 取决于你的数据库,有些数据库没有“嵌套事务”,【参考方案5】:

这取决于业务逻辑,如果 SP 是原子的,它应该实现自己的事务。如果您不这样做,您将在未来冒错误代码的风险,而不是创建包装事务。所以在回答你的问题时,我认为交易应该在 SP 内部进行。

当然,没有什么可以阻止你同时做这两件事,原子 SP 实现它们自己的事务,在该范围之外,可能已经存在其他更广泛的事务。

一般而言,在 SP 中使用事务创建时,您可能已经在事务范围内,在执行 Commit/Rollback 时必须为此实例编写代码。

【讨论】:

SP 内部的事务不只是加入外部事务范围,以便提交/回滚透明地工作吗?【参考方案6】:

我们在 Sproc 中执行以下操作,因为如果我们只是回滚它会增加外部 SProcs 中的事务计数,这可能会向应用程序生成一个警告 - 如果它不期望/处理它可能会导致应用程序错误。

但是,此方法仅回滚“本地”事务,因此外部“调用者”必须适当地解释返回值;或者使用 RAISERROR 或类似的。

BEGIN TRANSACTION MySprocName_01
SAVE  TRANSACTION MySprocName_02
...
IF @ErrorFlag = 0
BEGIN
    COMMIT TRANSACTION MySprocName_01
END
ELSE
BEGIN
    ROLLBACK TRANSACTION MySprocName_02
    COMMIT TRANSACTION MySprocName_01
END

【讨论】:

以上是关于应该在存储过程之外还是在内部指定事务?的主要内容,如果未能解决你的问题,请参考以下文章

oracle存储过程中临时表的使用,该怎么处理

雪花存储过程和事务:文档不清楚?

Spring 事务控制-存储过程事务

SQL存储过程等待并按顺序执行

mysql储存过程

DSP在工作时候,程序是在内部ram中,还是存储在外部sdram,然后在运行过程中,将程序实时载入其内部运行