【问题标题】:Create SQL Server procedure in a transaction在事务中创建 SQL Server 过程
【发布时间】:2018-08-05 10:20:34
【问题描述】:

我需要在 SQL Server 事务中创建两个过程。如果失败,我需要回滚此事务中的创建和任何其他执行的查询。我知道 create 语句必须是查询批处理中的第一个语句,但我需要知道如何处理多个批处理的事务。

BEGIN TRANSACTION

CREATE PROCEDURE [dbo].[SP_SP-1]
    @id BIGINT
AS
BEGIN
    SET NOCOUNT ON;

    -- SQL statements 
END
GO

CREATE PROCEDURE [dbo].[SP_SP-2]
    @id BIGINT  
AS  
BEGIN
    SET NOCOUNT ON;

    -- SP-2 statements
END
GO

UPDATE Table 
SET Value = '1.0.0.5' 

COMMIT TRANSACTION / ROLLBACK TRANSACTION 

【问题讨论】:

标签: sql sql-server tsql stored-procedures sql-server-2012


【解决方案1】:

以下是在一个事务中执行多个批处理的一种方法。这使用临时表来指示是否有任何批次出错并相应地执行最终的COMMITROLLLBACK

另一种方法是封装必须在单语句批处理中的语句(CREATE PROCEDURECREATE VIEW 等),但当必须对文字文本中的引号进行转义时,这会变得相当难看。

CREATE TABLE #errors (error varchar(5));
GO

BEGIN TRANSACTION
GO

CREATE PROCEDURE [dbo].[USP_SP-1]
    @id bigint 
AS
BEGIN
    SET NOCOUNT ON;
    -- SP Statments 
END;
GO
IF @@ERROR <> 0 INSERT INTO #errors VALUES('error');
GO

CREATE PROCEDURE [dbo].[USP_SP-2]
     @id BIGINT  
AS  
BEGIN
    SET NOCOUNT ON;
    -- SP-2 Statments
END;
GO
IF @@ERROR <> 0 INSERT INTO #errors VALUES('error');
GO

UPDATE Table SET Value='1.0.0.5' 
GO
IF @@ERROR <> 0 INSERT INTO #errors VALUES('error');
GO

IF EXISTS(SELECT 1 FROM #errors)
BEGIN
    IF @@TRANCOUNT > 0 ROLLBACK;
END
ELSE
BEGIN
    IF @@TRANCOUNT > 0 COMMIT;
END;
GO

IF OBJECT_ID(N'tempdb..#errors', 'U') IS NOT NULL
    DROP TABLE #errors;
GO

【讨论】:

  • 谢谢你,先生,我认为这是完美的一个
  • @ayman2000,如果这对你有用,请参阅What should I do when someone answers my question?
  • 我认为它需要修改 BEGIN IF @@TRANCOUNT > 0 ROLLBACK; END ELSE BEGIN IF @@TRANCOUNT > 0 COMMIT;结尾;我认为它需要修改为 IF @@TRANCOUNT = 0 COMMIT;
  • @ayman2000,除非@@TRANCOUNT &gt; 0,否则不能提交或回滚。我更改了脚本以删除围绕更新的 TRY/CATCH 并改用 @@ERROR,以便可以检测到该批次中的编译错误,并且无论 XACT_ABORT 会话设置如何,脚本都可以正常工作。
【解决方案2】:

我建议您在Handling Transactions in Nested SQL Server Stored Procedures 中了解有关此主题的更多信息。

从一开始,您的语法就是错误的。你不能开始一个事务然后创建一个过程,你需要做相反的事情:

CREATE PROCEDURE [dbo].[SP_SP-1]
@id bigint  
AS
BEGIN

   BEGIN TRY

      BEGIN TRANSACTION

           SET NOCOUNT ON;
        -- SP-2 Statments

          Update Table set Value='1.0.0.5'

   END TRY

   BEGIN CATCH 
    --handle error and perform rollback
         ROLLBACK  
      SELECT ERROR_NUMBER() AS ErrorNumber
      SELECT ERROR_MESSAGE() AS ErrorMessage   
   END CATCH
END

当尝试在事务范围内执行更新时,最好使用TRYCATCH

请阅读更多内容并使用我提供的链接进行调查以获得更大的图景。

【讨论】:

  • 我认为他想将事务用于 DDL 而不是 DML‌ 命令
  • 然而,无论他试图实现什么命令,语法都完全不正确,他需要为每个过程创建两个不同的事务。
  • @AfshinAmiri,事务仅在 DML 中有效。此外,它使用 Update 语句来设置列值,因此它不是 DDL。
  • 谢谢@Ajay2707c 我不想关注那句话,因为它与操作问题无关,只会让他更加困惑。
  • 你把事务放到Procedure中,我要做的就是把Procedure放到一个事务中
【解决方案3】:

要使用Transaction,你需要知道transaction是什么意思。它的含义是“处于提交状态或回滚状态的工作单元”。

所以当你使用事务时,你必须知道你在哪里声明和在哪里关闭。因此,您必须在父过程中开始和结束事务,它才能作为一个工作单元工作,即无论 DML 语句的查询执行次数是什么,它都使用相同的事务。

我不明白为什么您的更新语句也在程序和事务部分之外。

应该是(见我的 cmets,你可以使用 TRY Catch 和 c sharp 一样):

Create PROCEDURE [dbo].[SP_SP-1]
    @id bigint 
  AS
  BEGIN
   Begin Transaction
     SET NOCOUNT ON;

            -- SP Statments 
            Exec SP_SP-2 @id    --here you can pass the parameter to another procedure, but do not use transaction in another procedure, other wise it will create another transaction
    If @@Error > 0 than
        Rollback 
    Else
        Commit
    End
   END


 GO

 --Do not use transaction in another procedure, otherwise, it will create another transaction which has own rollback and commit and do not participate in the parent transaction
  Create PROCEDURE [dbo].[SP_SP-2]
     @id BIGINT  
    AS  
      BEGIN
      SET NOCOUNT ON;
      -- SP-2 Statments

       END
  GO

【讨论】:

  • 我找到了解决方案以执行程序作为执行脚本我将解决方案放入评论中
  • 对不起执行脚本?你可以发布你的代码@ayman2000,所以它也会有所帮助
  • 我需要在补丁文件上做很多任务,首先我需要创建程序和更新语句......这个更新语句与程序无关......一个补丁升级文件包含许多任务和如果发生任何错误,我需要回滚在此补丁文件中所做的所有更改
【解决方案4】:

我发现这个解决方案可以将程序作为字符串执行,这是执行我想要的解决方法

Begin Try
 Begin Transaction
        EXEC ('
                 Create PROCEDURE [dbo].[SP_1]
                     @id bigint 

                         AS
                             BEGIN  
                      SET NOCOUNT ON;
                                    SP-1
                                 END
                         GO
                   Create PROCEDURE [dbo].[SP_Inc_Discovery_RunDoc]
                       @id bigint
                             AS
                       BEGIN    
                              SET NOCOUNT ON;
                                     Sp-2
                              END')
 Update Table set Value='1.0.0.5' 
Commit  
End Try
 Begin Catch
Rollback  
Declare @Msg nvarchar(max)
Select @Msg=Error_Message();
RaisError('Error Occured: %s', 20, 101,@Msg) With Log;
End Catch

【讨论】:

  • 这不是好事@ayman2000,这是用来在事务中创建一个过程,过程创建后它将独立工作
  • @Ajay2707,这不起作用,因为GO 不是 T-SQL 语句,执行时会出错。 GO 是 SQL Server 工具及其某些 API(SMO 方法)识别的批处理终止符。您可以为每个 proc 使用单独的 EXEC 语句,但正如我在回答中提到的,当您需要在 proc 文本中转义引号时,它会变得很难看,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多