当满足交易的所有要求并记录交易信息时,我的程序会正确注册所有内容。
但是当提供错误信息时,信息不会被记录,但交易仍然存在,我不确定我做错了什么。
首先是记录交易信息的存储过程
/****** 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
事务日志中的
输入错误信息,例如从余额仅为100美元的帐户转移150美元会正确提出错误代码,但即使请求的资金不在那里,也不会取消交易
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 :(得分:1)
除非您的严重性级别为16或更高,否则Raiserror不会设置@@ Error。小于16的消息被视为信息性而非错误。请尝试以下代码进行验证:
RAISERROR('Insufficient Balance', 10, 3)
select @@Error; -- will be 0
RAISERROR('Insufficient Balance', 16, 3)
select @@Error; -- will be 50000
另外,请注意RAISERROR永远不会中断执行,除非你做了类似引发致命错误的事情,导致连接立即结束(你需要sysadmin权限)。因此,除了使用显式“返回”的地方之外,期望执行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
原因是任何成功的事件都会将@@ ERROR重置为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
因为它正在测试紧接在之前的更新语句的结果。