2017-08-02 55 views
0

當事務的所有要求都滿足並且記錄事務信息時,我的程序正確地註冊了所有事務。SQL事務在失敗時不記錄,但事務仍然通過

但是,當錯誤的信息給出的信息不記錄,但交易仍然通過,我不知道我做錯了什麼。

首先是存儲過程的日誌中的交易信息

/****** Object: StoredProcedure [dbo].[LogTransactionAttempt] Script Date: 8/1/2017 9:57:24 PM ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[LogTransactionAttempt] 
    (@ToUserAccountId int, 
    @FromUserAccountId int, 
    @TransferAmount money, 
    @CreditorWithdrawl nvarchar(50), 
    @TransferCode numeric(18,0)) 
AS 
BEGIN 
    INSERT INTO Transactions (FromUserAccountId, ToUserAccountId, TransferAmount, 
           CreditorWithdrawal, TransferCode, TransactionDateTime) 
    VALUES (@FromUserAccountId, @ToUserAccountId, @TransferAmount, 
      @CreditorWithdrawl, @TransferCode, GETDATE()) 

    RETURN @@IDENTITY 
END 

這裏是整個過程

/****** Object: StoredProcedure [dbo].[performTransaction] Script Date: 8/1/2017 9:57:05 PM ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[performTransaction] 
    (@ToUserAccountId int, 
    @FromUserAccountId int, 
    @TransferAmount money, 
    @CreditorWithdrawl nvarchar(50), 
    @TransferCode numeric(18,0)) 
AS 
BEGIN 
    DECLARE @FromUserAccountTest INT 

    SELECT @FromUserAccountTest = (SELECT Count(*) 
            FROM dbo.UserAccount 
            WHERE UserAccountId = @FromUserAccountID) 

    IF @FromUserAccountTest <> 1 
    BEGIN 
     RAISERROR('From Account Does Not Exist', 10, 1) 
    END 

    DECLARE @ToUserAccountTest INT 

    SELECT @ToUserAccountTest = (SELECT Count(*) 
           FROM dbo.UserAccount 
           WHERE UserAccountId = @ToUserAccountID) 

    IF @ToUserAccountTest <> 1 
    BEGIN 
     RAISERROR('To Account Does Not Exist', 10, 2) 
    END 

    -- At this point we can log the transaction 
    DECLARE @TransactionID INT 

    EXEC @TransactionID = dbo.LogTransactionAttempt @ToUserAccountId, @FromUserAccountId, @TransferAmount, @CreditorWithdrawl, @TransferCode 

    -- Check to see if sufficient balance 
    DECLARE @FromAccountBalance MONEY 

    SELECT @FromAccountBalance = (SELECT CreditBalance 
            FROM dbo.UserAccount 
            WHERE UserAccountID = @FromUserAccountID) 

    IF (@FromAccountBalance < @TransferAmount)  
    BEGIN 
     RAISERROR('Insufficient Balance', 10, 3) 
    END 

    -- Now we can start the transaction 
    BEGIN TRANSACTION 
     UPDATE UserAccount 
     SET CreditBalance = CreditBalance - @TransferAmount 
     WHERE UserAccountId = @FromUserAccountID 

     IF (@@ERROR <> 0) 
     BEGIN 
      ROLLBACK TRANSACTION /* if errors - rollback transaction */ 
      RETURN 
     END 

     UPDATE UserAccount 
     SET CreditBalance = CreditBalance + @TransferAmount 
     WHERE UserAccountID = @ToUserAccountID 

     IF (@@ERROR <> 0) 
     BEGIN 
      ROLLBACK TRANSACTION /*if errors - rollback transaction */ 
      RETURN 
     END 

     UPDATE dbo.Transactions 
     SET Successful = 1 
     WHERE TransactionID = @TransactionID 

     IF (@@ERROR <> 0) 
     BEGIN 
      ROLLBACK TRANSACTION /* if errors - rollback transaction */ 
      RETURN 
     END 

     -- Transaction 
     COMMIT TRANSACTION 

END -- Procedure 

就像我說的一切都運行完美,當輸入是正確的,但如果有一個不好的輸入說不存在帳戶或資金不足,它不記錄失敗,但交易仍然通過

編輯 嘗試從10切換到16沒有影響

例子的正確的事務移動從帳戶11 $ 100爲$ 100的平衡以說明22無平衡

USE [Transaction] 
GO 

DECLARE @return_value int 

EXEC @return_value = [dbo].[performTransaction] 
    @ToUserAccountId = 22, 
    @FromUserAccountId = 11, 
    @TransferAmount = 100, 
    @CreditorWithdrawl = N'credit', 
    @TransferCode = 1 

SELECT 'Return Value' = @return_value 

GO 

該正確的條目返回

1017 22 11 100.0000 credit 1 2017-08-02 10:19:23.110 yes 

在交易日誌中

輸入錯誤信息,例如從一個賬戶轉賬150美元,餘額只有100美元ES錯誤代碼正常,但不會取消,即使所請求的錢是不是都在那裏

USE [Transaction] 
GO 

DECLARE @return_value int 

EXEC @return_value = [dbo].[performTransaction] 
    @ToUserAccountId = 22, 
    @FromUserAccountId = 11, 
    @TransferAmount = 150, 
    @CreditorWithdrawl = N'credit', 
    @TransferCode = 2 

SELECT 'Return Value' = @return_value 

GO 

事務返回

(1 row(s) affected) 
Msg 50000, Level 16, State 3, Procedure performTransaction, Line 72 [Batch Start Line 2] 
Insufficient Balance 

(1 row(s) affected) 

(1 row(s) affected) 

(1 row(s) affected) 

(1 row(s) affected) 

所以有錯誤顯示的消息的下面,但錯誤的交易沒有登錄,但交易仍通過導致負平衡

USE [Transaction] 
GO 
/****** Object: StoredProcedure [dbo].[LogTransactionAttempt] Script Date: 8/2/2017 9:20:54 PM ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 


ALTER PROCEDURE [dbo].[LogTransactionAttempt] 


(


    @ToUserAccountId int, 
    @FromUserAccountId int, 
    @TransferAmount money, 
    @TransferCode numeric(18,0) 
) 

AS 

BEGIN 

    INSERT INTO Transactions 

    (

    UserAccountId, 
    TransferAmount, 
    CreditorWithdrawal, 
    TransferCode, 
    TransactionDateTime 
) 

    VALUES 

    (
    @FromUserAccountId, 
    @TransferAmount, 
    'Withdrawl', 
    @TransferCode, 
    GETDATE() 
) 
    , 
    (
    @ToUserAccountId, 
    @TransferAmount, 
    'Credit', 
    @TransferCode, 
    GETDATE() 
) 



    RETURN @@IDENTITY 



    END 
+0

錯誤級別爲10的Raiserror可能太低而無法正確捕獲。我試着把它撞到16.比如說,如果你沒有使用try/catch塊,你可能還需要設置xact_abort。這應該至少可以防止隨後的事務繼續並在您遇到raiserror時進行承諾 – Xedni

回答

1

RAISERROR不設置@@ ERROR去,除非你的嚴重性級別爲16或更高。小於16的消息被認爲是信息性的,而不是錯誤。試試下面的代碼來驗證:

RAISERROR('Insufficient Balance', 10, 3) 
select @@Error; -- will be 0 
RAISERROR('Insufficient Balance', 16, 3) 
select @@Error; -- will be 50000 

另外,注意RAISERROR將永遠不會中斷執行,除非你做這樣的事情提高並由此導致連接立即結束致命錯誤(你需要系統管理員權限)。因此,除了使用顯式「返回」的地方以外,期望執行RAISERROR後的所有代碼。

閱讀更多關於RAISERROR和破壞:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/483d6be7-6518-41c9-8138-aa1412ae8252/raiseerror-to-stop-execution?forum=transactsql

除了需要

DECLARE @errcode INT 

after 

DECLARE @FromUserAccountTest INT; 

的添加

select @errcode = @@ERROR 

immediately after each raiserror 

原因是任何成功的事件將錯誤復位@@ 0 - 所以下面所有的重置您的@@ ERROR變量的0;

SELECT @FromUserAccountTest = (SELECT Count(*) 
           FROM dbo.UserAccount 
           WHERE UserAccountId = @FromUserAccountID) 

SELECT @FromUserAccountTest = (SELECT Count(*) 
           FROM dbo.UserAccount 
           WHERE UserAccountId = @FromUserAccountID) 


EXEC @TransactionID = dbo.LogTransactionAttempt @ToUserAccountId, @FromUserAccountId, @TransferAmount, @CreditorWithdrawl, @TransferCode 

    UPDATE UserAccount 
    SET CreditBalance = CreditBalance - @TransferAmount 
    WHERE UserAccountId = @FromUserAccountID 

後來終於改變你的

IF @@ERROR <> 0 

第一次出現於

IF @@errcode <> 0 

離開第二次出現的

IF @@ERROR <> 0 

,因爲它測試的更新語句的結果立即p後退。

+0

錯誤的發生與錯誤信息的提供,錯誤消息的正確彈出,事務繼續,我遇到問題和錯誤在正確的事務處理時,事務不能正確記錄。如何讓它記錄成功和失敗的交易,同時讓它回滾任何錯誤的交易?就像你提到的那樣,我會嘗試從10轉換到16。編碼不是我強大的技能之一,所以如果我錯過了一些極其簡單的解決方法,我很抱歉。 – user7143384

+0

你是什麼意思「不記錄失敗?」你是指調用你的[LogTransactionAttempt]?你的意思是它沒有寫到你的交易表中,或者它表明它成功了?如果是第一個,你能否提供一個最小的工作樣本以及一些樣本數據和表格定義以供我複製:-)?如果是第二個,則更改嚴重性級別應糾正該問題。此外,代碼縮進在未來也很有用:-)。 –

+0

當交易完成而沒有任何錯誤時,它會在表格中記錄關於交易的信息,該部分工作正常。當錯誤信息引入查詢時,如不存在的帳戶,事務完成但不記錄,而不是回滾事務並在事務表中記錄失敗的事務信息。 – user7143384