存储过程事务

Posted

技术标签:

【中文标题】存储过程事务【英文标题】:Stored Procedure Transaction 【发布时间】:2011-09-09 07:31:09 【问题描述】:

我以前从未使用过事务、提交和回滚,现在我需要使用一个。我已经在网上查了一些例子,以确保我实际上正确地使用了这个,但我仍然不确定我是否正确地编码了这个。如果这看起来正确,我希望有人可以审查并建议我。

基本上我有 2 个数据库用于一个应用程序。一个是存档——这意味着不再被用户操作的数据将被移动到这个数据库中。但是如果他们需要它,我会将所需的数据移回主数据库以供使用。我的存储过程如下:

CREATE PROCEDURE [dbo].[spReopenClosed] 
(
    @Return_Message VARCHAR(1024) = ''  OUT,        
    @IID        uniqueidentifier,
    @OpenDate   smalldatetime,
    @ReopenedBy uniqueidentifier
)
AS
BEGIN
    SET NOCOUNT ON;

/******************************
*  Variable Declarations
*******************************/
    DECLARE     @ErrorCode  int  



/******************************
*  Initialize Variables
*******************************/

    SELECT @ErrorCode = @@ERROR

    IF @ErrorCode = 0

    BEGIN TRANSACTION
        /****************************************************************************
        * Step 1
        * Copy the Closed from the Archive
        ****************************************************************************/
        INSERT INTO OPS.dbo.SM_T_In
        SELECT          
        FROM OPS_ARCHIVE.Archive.SM_T_In    W
        WHERE W.GUID = @IID
            AND W.OpenDate = @OpenDate


        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in Copying from the archive', 16, 1)
                RETURN
            END


        /****************************************************************************
        * Step 2
        * copy the notes
        ****************************************************************************/
        INSERT INTO OPS.dbo.SM_T_Notes
        SELECT 
        FROM OPS_ARCHIVE.Archive.SM_T_Notes W
        WHERE W.GUID = @IID

        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in copying the notes', 16, 1)
                RETURN
            END

        /****************************************************************************
        * Step 3
        * Delete the from the Archive - this will also delete the notes
        ****************************************************************************/
        DELETE
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE OPS_ARCHIVE.Archive.SM_T_In.GUID = @IID

        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in deleting the items from the Archive', 16, 1)
                RETURN
            END

        COMMIT

        BEGIN
            SELECT  @ErrorCode  = @@ERROR

            IF @ErrorCode = 0
                    SELECT  @Return_Message = 'All data was moved over'
        END



/*************************************
*  Get the Error Message for @@Error
*************************************/
    IF @ErrorCode <> 0
    BEGIN
        SELECT  @Return_Message = [Description]     -- Return the SQL Server error
          FROM  master.dbo.SYSMESSAGES
         WHERE  error = @ErrorCode
    END

/*************************************
*  Return from the Stored Procedure
*************************************/
    RETURN @ErrorCode                               -- =0 if success,  <>0 if failure
END

我有两个插入,它们从存档数据库的 2 个表中移动数据。如果这些插入成功,那么我将从存档数据库中删除数据。如果对此有任何反馈,我将不胜感激,我需要确保我做得正确。

谢谢

【问题讨论】:

SQL Server 的哪个版本?它在方法上有很大的不同。 【参考方案1】:

哦,好吧,我按照您的要求使用 TRY CATCH 和 TRANSACTION 概念快速重写了您的 SP,但我没有检查它。

此代码适用于 SQL 2005/2008

如果此反馈对您有用,请告诉我

CREATE PROCEDURE [dbo].[spReopenClosed] 
(
    @Return_Message VARCHAR(1024) = ''  OUT,        
    @IID        uniqueidentifier,
    @OpenDate   smalldatetime,
    @ReopenedBy uniqueidentifier
)
AS

    SET NOCOUNT ON;

/******************************
*  Variable Declarations
*******************************/
    DECLARE     @ErrorCode  int  
    DECLARE     @ErrorStep  varchar(200)

/******************************
*  Initialize Variables
*******************************/

    SELECT @ErrorCode = @@ERROR

BEGIN TRY

    BEGIN TRAN
        /****************************************************************************
        * Step 1
        * Copy the Closed from the Archive
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in Copying from the archive';

        INSERT INTO OPS.dbo.SM_T_In
        SELECT *         
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE GUID = @IID
            AND W.OpenDate = @OpenDate


        /****************************************************************************
        * Step 2
        * copy the notes
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in copying the notes'

        INSERT INTO OPS.dbo.SM_T_Notes
        SELECT *
        FROM OPS_ARCHIVE.Archive.SM_T_Notes
        WHERE GUID = @IID

        /****************************************************************************
        * Step 3
        * Delete the from the Archive - this will also delete the notes
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in deleting the items from the Archive'

        DELETE
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE OPS_ARCHIVE.Archive.SM_T_In.GUID = @IID

    COMMIT TRAN

    SELECT  @ErrorCode  = 0, @Return_Message = 'All data was moved over'

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN @ErrorCode                               -- =0 if success,  <>0 if failure

END TRY

BEGIN CATCH
    /*************************************
    *  Get the Error Message for @@Error
    *************************************/
    IF @@TRANCOUNT > 0 ROLLBACK

    SELECT @ErrorCode = ERROR_NUMBER()
        , @Return_Message = @ErrorStep + ' '
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '
        + cast(ERROR_LINE() as varchar(20)) + ' ' 
        + ERROR_MESSAGE() + ' > ' 
        + ERROR_PROCEDURE()

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN @ErrorCode                               -- =0 if success,  <>0 if failure

END CATCH

【讨论】:

好例子!谢谢 我尝试使用与上述类似的代码在不同点强制出错,并且效果很好。谢谢!【参考方案2】:

首先,数据库相当可靠。如果他们失败了,你会遇到比处理单个交易更大的问题。所以我的反馈是你对一个简单的交易有太多的错误检查。插入失败是一个不寻常的事件,您通常不会编写代码来处理它。

其次,这段代码实际上不会“捕获”错误:

IF @ErrorCode <> 0

SQL 语句中的错误将中止存储过程并返回给客户端。您必须try ... catch 才能实际处理存储过程中的错误。

第三,我尽量避免raiserr。它可以在服务器端和客户端做意想不到的事情。相反,请考虑使用output 参数将错误信息返回给客户端程序。

【讨论】:

以上是关于存储过程事务的主要内容,如果未能解决你的问题,请参考以下文章

关于sqlserver存储过程事务锁的问题

mysql存储过程与事务

mysql-高级功能(触发器存储过程视图事务)

事务、存储过程和 PDO

Mysql从入门到入魔——8. 视图存储过程事务处理

sqlserver 存储过程 使用事务,说明在下边,求大神指教!