【发布时间】:2018-01-09 01:30:17
【问题描述】:
当交易的所有要求都得到满足时,我的程序会正确注册所有内容并记录交易信息。
但是当给出错误信息时,信息不会被记录,但交易仍然会进行,我不确定我做错了什么。
首先是记录事务信息的存储过程
/****** 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 无效
将 100 美元从余额为 100 美元的帐户 11 转移到没有余额的帐户 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
【问题讨论】:
-
错误级别为 10 的 Raiserror 可能太低而无法正确捕获。我会尝试将它提高到 16。如果您没有使用 try/catch 块,您可能还需要将 xact_abort 设置为 on。这至少应该防止后续交易在您遇到 raiserror 时继续并提交