【问题标题】:Is having a stored procedure that calls other stored procedures bad?有一个调用其他存储过程的存储过程不好吗?
【发布时间】:2009-07-31 20:58:37
【问题描述】:

我正在尝试使长存储过程更易于管理,是否有一个调用其他存储过程的存储过程是错误的,例如我想要一个将数据插入表的存储过程,具体取决于类型将附加信息插入到该类型的表中,例如:

BEGIN TRANSACTION

        INSERT INTO dbo.ITSUsage (
            Customer_ID,
            [Type],
            Source
        ) VALUES ( 
            @Customer_ID,
            @Type,
            @Source
            )
    SET @ID = SCOPE_IDENTITY()  

    IF @Type = 1
        BEGIN
                  exec usp_Type1_INS @ID, @UsageInfo 
            END
        IF @TYPE = 2
                BEGIN
                  exec usp_Type2_INS @ID, @UsageInfo 
            END

    IF (@@ERROR <> 0)
        ROLLBACK TRANSACTION
    ELSE
        COMMIT TRANSACTION      

或者这是我应该在我的应用程序中处理的事情?

【问题讨论】:

  • 你可能想放弃 @@ERROR 并使用 BEGIN TRY(try catch)和 XACT_STATE()
  • 假设这是 2k5 或更高版本...

标签: sql sql-server


【解决方案1】:

是的,这很糟糕。虽然 SQL Server 确实支持并允许一个存储过程调用另一个存储过程。如果可能,我通常会尽量避免这种设计。我的理由?

single responsibility principle

【讨论】:

  • 那么实际上确实调用其他存储过程的那段代码呢?不违反这个原则吗?
【解决方案2】:

我们一直从其他 proc 调用 proc。否则很难/不可能分割数据库密集型(或仅数据库)应用程序。

【讨论】:

  • 同意,但如果父 proc 可能回滚,请注意调用链中可能执行或需要执行提交的 proc。
  • 是的。这可能很棘手——您实际上处于一个沙箱中,因此您必须担心其他 proc 将对共享环境做什么。
  • 还要注意 INSERT EXEC 语句不能嵌套。也就是说,调用其他过程并将返回的记录集存储在临时表中的过程。
  • 有没有一种方法可以在存储过程中从存储过程中进行选择。
【解决方案3】:

从另一个过程内部调用一个过程是完全可以接受的。

但是,在 Transact-SQL 中依赖 @@ERROR 很容易失败。举个例子,你的代码。它将无法检测到插入失败,以及在调用过程中产生的任何错误。这是因为@@ERROR 在每条语句执行时都会重置,并且只保留最后一条语句的结果。我有一个显示correct template of error handling in Transact-SQL 和事务嵌套的博客条目。 Erland Sommarskog 也有一篇文章,很长一段时间以来,reference read on error handling in Transact-SQL

【讨论】:

    【解决方案4】:

    不,完全可以接受。

    【讨论】:

      【解决方案5】:

      绝对不会。

      我已经看到巨大的存储过程在做 20 种不同的事情,这些事情如果被重构为更小的、单一用途的事情,它们会真正受益。

      【讨论】:

        【解决方案6】:

        只要它在同一个数据库模式中,我认为它是完全可以接受的。重用总是有利于复制。这就像调用某个应用层中的方法。

        【讨论】:

          【解决方案7】:

          完全没有,我什至会说,推荐它的原因与在代码中创建方法的原因相同

          【讨论】:

          • 这正是我想做的原因
          【解决方案8】:

          一个存储过程调用另一个存储过程很好。只是你可以去的嵌套级别有一个限制。

          在 SQL Server 中,当前嵌套级别由 @@NESTLEVEL 函数返回。

          请在此处查看存储过程嵌套部分http://msdn.microsoft.com/en-us/library/aa258259(SQL.80).aspx

          干杯

          【讨论】:

            【解决方案9】:

            没有。它促进重用并允许将功能组件化。

            【讨论】:

              【解决方案10】:

              正如其他人所指出的,这是完全可以接受的,并且是避免重复功能所必需的。

              但是,在 Transact-SQL 中,请注意嵌套存储过程调用中的事务:您需要在发出 rollback transaction 之前检查 @@TRANCOUNT,因为它会回滚所有嵌套事务。查看此article 以获得深入的解释。

              【讨论】:

                【解决方案11】:

                在我们的 IT 领域,我们使用存储过程来整合存储过程和触发器(如果适用)的通用代码。为了避免 SQL 源代码重复,它实际上也是强制性的。

                【讨论】:

                  【解决方案12】:

                  当然,这个问题的一般答案是“不”——这是编写 SQL 存储过程的正常甚至首选方式。

                  但在您的具体情况下,这可能不是一个好主意。

                  如果您在应用程序(Java、.Net 等)中维护一组支持数据访问层 (DAO) 的存储过程,那么简化和相对精简的数据库层(让我们这样称呼存储过程)将使您受益整体设计。因此,拥有广泛的存储过程调用图可能确实不利于维护和支持此类应用程序中的整体数据访问逻辑。

                  我倾向于在 DAO 和数据库层之间更统一地分配逻辑,以便存储过程代码适合单个函数调用。

                  【讨论】:

                    【解决方案13】:

                    添加到其他张贴者的正确 cmets,原则上没有错,但您需要注意 执行时间,以防程序被外部应用程序调用,例如符合特定的超时

                    如果您从 Web 应用程序调用存储过程 的典型示例:当默认超时启动时,因为您的执行链需要更长的时间,即使存储过程提交,您也会在 Web 应用程序中遇到故障正确。 如果您从外部服务调用,也会发生同样的情况。 这可能会导致您的应用程序出现不一致的行为,从而触发外部服务中的错误管理例程等。

                    如果您遇到这种情况,我所做的就是打破调用链,使用 Service Broker 将长时间执行的子调用重定向到不同的进程。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2014-09-17
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-05-05
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多