在事务中创建SQL Server过程

时间:2018-08-05 10:20:35

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

我需要在SQL Server事务中创建两个过程。如果失败,则需要回退此事务中的create和其他执行的查询。我知道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 

4 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:2)

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

另一种方法是封装必须成单语句批处理的语句(CREATE PROCEDURECREATE VIEW等),但是当必须对文字文本中的引号进行转义时,这会变得很丑陋。 / p>

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

答案 2 :(得分:1)

要使用事务,您需要知道事务的含义。这是“工作单元处于提交状态或回滚状态”的意思。

因此,在使用事务时,必须知道声明的位置和关闭的位置。因此,您必须仅在父过程中开始和结束事务,否则它将作为一个工作单元工作,即,无论查询DML语句执行什么,它都使用相同的事务。

我也不明白为什么您的更新语句也超出了过程和事务部分。

应该是(请参阅我的评论,您可以使用与c Sharp相同的TRY Catch):

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

答案 3 :(得分:0)

我找到了将该解决方案作为字符串执行程序来执行的解决方案,这是一种执行我想要的方法的解决方法

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