是否有必要在此代码中放置交易?

时间:2016-03-17 12:01:35

标签: sql sql-server database sql-server-2008 tsql

我的主管要求我不要在此代码中放置事务和提交等,因为他说在此过程中放置​​事务是没用的。他经验丰富,我不能直接与他争辩,所以需要你的观点吗?

ALTER PROCEDURE [Employee].[usp_InsertEmployeeAdvances](
      @AdvanceID        BIGINT,
      @Employee_ID      INT,
      @AdvanceDate      DATETIME,
      @Amount           MONEY,
      @MonthlyDeduction MONEY,
      @Balance          MONEY,
      @SYSTEMUSER_ID    INT,
      @EntryDateTime    DATETIME = NULL,
      @ProcedureType    SMALLINT)
AS
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION [Trans1]
        IF EXISTS
           (
              SELECT *
              FROM Employee.Advance
              WHERE AdvanceID = @AdvanceID
           )
        BEGIN
            --UPDATION OF THE RECORD
            IF @ProcedureType = 1
            BEGIN
                SET @Amount = @Amount * -1;
            END
            UPDATE Employee.Advance
            SET
                  Employee_ID = @Employee_ID,
                  AdvanceDate = @AdvanceDate,
                  Amount = @Amount,
                  MonthlyDeduction = @MonthlyDeduction,
                  Balance = @Balance,
                  EntryDateTime = GETDATE()
            WHERE AdvanceID = @AdvanceID
        END
        ELSE
        BEGIN
            DECLARE @LastRecordID INT
            DECLARE @LastBalance MONEY
            SET @LastRecordID =
               (
                  SELECT MAX(EA.AdvanceID)
                  FROM Employee.Advance EA
                  WHERE EA.Employee_ID = @Employee_ID
               )
            SET @LastBalance =
               (
                  SELECT EA.Balance
                  FROM Employee.Advance EA
                  WHERE EA.AdvanceID = ISNULL(@LastRecordID, 0)
               )
            IF(@ProcedureType = 0) --Advances
            BEGIN
                SET @Balance = ISNULL(@LastBalance, 0) + @Amount
                INSERT INTO Employee.Advance
                                            (Employee_ID,
                                             AdvanceDate,
                                             Amount,
                                             MonthlyDeduction,
                                             Balance,
                                             User_ID,
                                             EntryDateTime
                                            )
                VALUES
                       (@Employee_ID,
                        @AdvanceDate,
                        @Amount,
                        @MonthlyDeduction,
                        @Balance,
                        @SYSTEMUSER_ID,
                        GETDATE())
            END
            ELSE --Receivings
            BEGIN
                IF NOT EXISTS
                   (
                      SELECT *
                      FROM Employee.Advance EA
                      WHERE EA.Employee_ID = @Employee_ID
                            AND EA.Balance > 0
                            AND EA.AdvanceID =
                         (
                            SELECT MAX(AdvanceID)
                            FROM Advance
                            WHERE Employee_ID = @Employee_ID
                         )
                   )
                BEGIN
                    RAISERROR('This Employee has no advances history', 16, 1)
                    RETURN
                    --Select 0                  
                END
                ELSE
                BEGIN
                    SET @Balance = ISNULL(@LastBalance, 0) - @Amount
                    INSERT INTO Employee.Advance
                                                (Employee_ID,
                                                 AdvanceDate,
                                                 Amount,
                                                 MonthlyDeduction,
                                                 Balance,
                                                 User_ID,
                                                 EntryDateTime
                                                )
                    VALUES
                           (@Employee_ID,
                            @AdvanceDate,
                            -1 * @Amount,
                            @MonthlyDeduction,
                            @Balance,
                            @SYSTEMUSER_ID,
                            GETDATE())
                END
            END
        END
        COMMIT TRANSACTION [Trans1]
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION [Trans1]
    END CATCH
END

4 个答案:

答案 0 :(得分:1)

ALTER PROCEDURE [Employee].[usp_InsertEmployeeAdvances]
(
      @AdvanceID        BIGINT,
      @Employee_ID      INT,
      @AdvanceDate      DATETIME,
      @Amount           MONEY,
      @MonthlyDeduction MONEY,
      @Balance          MONEY,
      @SYSTEMUSER_ID    INT,
      @EntryDateTime    DATETIME = NULL,
      @ProcedureType    SMALLINT
)
AS BEGIN

    SET NOCOUNT ON

    IF EXISTS (
        SELECT 1
        FROM Employee.Advance
        WHERE AdvanceID = @AdvanceID
    )
    BEGIN

        UPDATE Employee.Advance
        SET
                Employee_ID = @Employee_ID,
                AdvanceDate = @AdvanceDate,
                Amount = CASE WHEN @ProcedureType = 1 THEN -@Amount ELSE @Amount END,
                MonthlyDeduction = @MonthlyDeduction,
                Balance = @Balance,
                EntryDateTime = GETDATE()
        WHERE AdvanceID = @AdvanceID

    END
    ELSE BEGIN

        DECLARE
              @LastRecordID INT
            , @LastBalance MONEY
            , @IsBalance BIT

        SELECT @LastRecordID = MAX(AdvanceID)
        FROM Employee.Advance
        WHERE Employee_ID = @Employee_ID

        SELECT
            @LastBalance = Balance,
            @IsBalance = CASE WHEN Balance > 0 THEN 1 ELSE 0 END
        FROM Employee.Advance
        WHERE AdvanceID = ISNULL(@LastRecordID, 0)

        IF ISNULL(@IsBalance, 0) = 0 BEGIN

            RAISERROR('This Employee has no advances history', 16, 1)
            RETURN 

        END
        ELSE BEGIN

            INSERT INTO Employee.Advance(Employee_ID, AdvanceDate, Amount, MonthlyDeduction, Balance, [User_ID], EntryDateTime)
            SELECT
                @Employee_ID,
                @AdvanceDate,
                CASE WHEN @ProcedureType = 0 THEN @Amount ELSE -@Amount END,
                @MonthlyDeduction,
                ISNULL(@LastBalance, 0) + CASE WHEN @ProcedureType = 0 THEN @Amount ELSE -@Amount END,
                @SYSTEMUSER_ID,
                GETDATE()

        END

    END

END

答案 1 :(得分:1)

这是一个改变了的答案,因为我没有读完整个问题

如果没有交易,如果同时调用并且记录不存在那么两者都可以插入,而且可能会出现@Balance错误

是的,交易有用的目的

答案 2 :(得分:0)

我从不把交易放在特定的工作中,因为你永远不知道它什么时候会被合并到另一个工作中。只有来电者才能知道。要使用陈旧的示例,您可能会认为创建订单和添加项目应该是一个足够公平的交易。在轨道下方,某些呼叫功能可能希望将信用检查或帐户创建的结果作为其一部分包括在内。所以基本上在低级别你不能知道*如果你在交易的背景下或不是这样,那么对提交的严格要求就没那么重要了。同样,回滚有点不对 - 你永远不知道在调用者的上下文中特定错误是多么致命,所以只需抛出异常并让客户决定如何管理它。

*你可以,但通常更容易不关心。

答案 3 :(得分:0)

由于现在正在编写存储过程,因此事务不会添加任何内容。只有其中一个修改会运行,如果它失败,那么无论如何它都会回滚。另外值得注意的是,修改后没有任何反应。如果在其中一个更新后有一些额外的代码,则可能需要进行交易。

然而,进行该交易的成本是多少?您是否期望此代码永远不会改变?未来的变化可能会使交易变得必要,而不会显而易见。鉴于您的存储过程的性质,我发现很难相信交易存在缺点。

要处理RAISERROR区块内的TRY..CATCH

BEGIN TRANSACTION

BEGIN TRY


    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF (@@TRANCOUNT > 0)
        ROLLBACK TRANSACTION

    EXEC dbo.LogErrorAndRethrow
END CATCH

LogErrorAndRethrow的代码如下:

CREATE PROCEDURE dbo.LogErrorAndRethrow
    @LogError BIT = 1
AS
BEGIN
    DECLARE
        @error_number   INT,
        @error_message  NVARCHAR(MAX),
        @error_severity INT,
        @error_state    INT,
        @error_procedure NVARCHAR(200),
        @error_line     INT

    SELECT
        @error_number = ERROR_NUMBER(),
        @error_message = ERROR_MESSAGE(),
        @error_severity = ERROR_SEVERITY(),
        @error_state = ERROR_STATE(),
        @error_procedure = COALESCE(ERROR_PROCEDURE(), '<Unknown>'),
        @error_line = ERROR_LINE()

    IF (@LogError = 1)
    BEGIN
        EXEC dbo.InsertAuditLog
            @UserID = 0,
            @AuditType = 'Error',
            @ModuleName = @error_procedure,
            @Message = @error_message
    END

    -- Rebuild the error message with parameters so that all information appears in the RAISERROR
    SELECT @error_message = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + ERROR_MESSAGE()

    RAISERROR(@error_message, @error_severity, 1, @error_number, @error_severity, @error_state, @error_procedure, @error_line)
END

InsertAuditLog基本上只是插入日志表。