SQL存储过程不处理来自嵌套存储过程的错误

时间:2014-08-01 16:15:44

标签: sql sql-server stored-procedures

我有两个存储过程,一个嵌套在另一个中。当调用嵌套存储过程时,此时它应该在出现外键约束冲突时出错,然后回滚先前的insert以插入到ProductLicense表中。嵌套过程不会对数据库执行任何操作,因为外键违规但调用存储过程没有捕获错误并回滚。如果我自己执行嵌套存储过程,它会返回错误547外键冲突。

如何让两个存储过程协同工作?

外部程序:

ALTER PROCEDURE [dbo].[AddNewLicense2_i]
    -- Add the parameters for the stored procedure here
    @customerId nvarchar(10),
    @licenseModeId int,
    @licenseModeProgramId int,
    @createdBy int,
    @updateBy int,
    @systemId nvarchar(50),
    @productId int

AS
BEGIN TRY
    BEGIN TRANSACTION
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;
        --SET XACT_ABORT ON;  --used for automatic rollback when an error occurs    

        DECLARE @tempDays INT
        DECLARE @programCornerAmt INT
        DECLARE @tempEndDate DATETIME
        DECLARE @tempExpDate DATETIME
        DECLARE @err INT

        SET @err = 0

        /*SET @tempDays = (SELECT lmp.TimeoutDays
                         FROM LicenseModeProgram lmp 
                         WHERE lmp.LicenseModeProgramId = @licenseModeProgramId)*/

        SELECT @tempDays = TimeoutDays, @programCornerAmt = MonthlyCornersAmount
        FROM LicenseModeProgram
        WHERE LicenseModeProgramId = @licenseModeProgramId

        --Build Expiration and End Dates.
        IF @tempDays = NULL --then this is NOT a time rental or metered system
            BEGIN
                SET @tempEndDate = NULL
                SET @tempExpDate = NULL
            END
        ELSE
            BEGIN
                SET @tempEndDate = DATEADD("d", @tempDays, GETDATE())
                SET @tempExpDate = DATEADD("d", @tempDays, GETDATE())
            END 

        -- Create new product license record
        INSERT INTO ProductLicense (CustomerId, LicenseModeId, LicenseModeProgramId, CreatedBy, UpdatedBy, SystemId, ProductId, ExpirationDate, LicenseEndDate)
        VALUES (@customerId, @licenseModeId, @licenseModeProgramId, @createdBy, @updateBy, @systemId, @productId, @tempExpDate, @tempEndDate)

        IF @licenseModeId = 4 AND @systemId  NULL AND @programCornerAmt  NULL
            --call stored procedure to add corners to the customer account
            EXECUTE @err = AddMeteredTx_i @systemId, 1, 1, @programCornerAmt , 'Initial License Creation'

        PRINT @err

    COMMIT TRANSACTION
END TRY
BEGIN CATCH 
    RAISERROR('Failed to Create License', 11, 2)
    ROLLBACK TRANSACTION
    RETURN 1
END CATCH

    --COMMIT TRANSACTION
RETURN 0
GO

内部程序:

ALTER PROCEDURE [dbo].[AddMeteredTx_i]
    -- Add the parameters for the stored procedure here

    @systemId nvarchar(50),
    @activityEventId int,
    @createdBy int,
    @amount int,
    @notes text
AS
BEGIN TRY
    BEGIN TRANSACTION
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;
        --SET XACT_ABORT ON;  --used for automatic rollback when an error occurs

        INSERT INTO CustomerAccountActivity (SystemId, ActivityEventId, CreatedBy, Amount, Notes)
        VALUES (@systemId, @activityEventId, @createdBy, @amount, @notes)

        UPDATE CustomerAccount
        SET MeteredBalance = (SELECT MeteredBalance FROM CustomerAccount WHERE SystemId = @systemId) + @amount
        WHERE SystemId = @systemId

    COMMIT TRANSACTION
END TRY
BEGIN CATCH

    RAISERROR('Error Update to Customer Account Record ', 11, 2)
    ROLLBACK TRANSACTION
    RETURN 1

    --COMMIT TRANSACTION
END CATCH

RETURN 0
GO

1 个答案:

答案 0 :(得分:6)

使用@@Error使用这样的调用堆栈捕获错误可能会有问题。使用TRY/CATCH

更加可靠

基本格式为:

BEGIN TRY
<BEGIN TRAN>

... do stuff ...
<COMMIT TRAN>
END TRY
BEGIN CATCH
<ROLLBACK TRAN>
... do error stuff like re-raise the error to outer scope ...


END CATCH

尝试中遇到的任何错误都会自动将您带到CATCH块而无需额外检查。