2017-08-02 64 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

相关问题