[英]How to figure out which part of query is causing error?
After Running this query, I am getting one custom Error:运行此查询后,我收到一个自定义错误:
Debit account balance can not be less than 0. somemail@7dmail.com/123/xxx/123456
借方账户余额不能小于0。somemail@7dmail.com/123/xxx/123456
And Two regular errors:和两个常规错误:
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements.
EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。 Previous count = 2, current count = 0. The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
先前计数 = 2,当前计数 = 0。ROLLBACK TRANSACTION 请求没有对应的 BEGIN TRANSACTION。
I think, that transaction errors happen because something is throwing exception before transaction is committed.我认为,发生事务错误是因为在事务提交之前发生了异常。 Custom Error is from another query(AddJournalEntry) which is written below.
自定义错误来自下面写的另一个查询(AddJournalEntry)。 I can not see connection between these two queries.
我看不到这两个查询之间的联系。
Query:询问:
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[RevokeOrder]
@OrderId int = null
--,@EntryId int OUTPUT
AS
declare @OrderTypeId nvarchar(30)
declare @MasterEntryId int
declare @NewEntryId int
declare @CustomerGuid uniqueidentifier
declare @Debit int
declare @Credit int
declare @Explanation nvarchar(100)
declare @Amount decimal(18, 8)
declare @AmountFilled decimal(18, 8)
declare @Total decimal(18, 8)
declare @TotalLeft decimal(18, 8)
declare @AmountLeft decimal(18, 8)
declare @AssetId nvarchar(30)
declare @QuoteAssetId nvarchar(30)
declare @QuotePrice decimal(18, 8)
declare @AssetReserveAccountId int
declare @AssetAccountId int
declare @EntryAmount decimal(18, 8)
BEGIN;
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET XACT_ABORT ON;
SET NOCOUNT ON;
print ''
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print 'Start RevokeOrder procedure'
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print ''
begin tran
select
@OrderTypeId = OrderTypeId,
@CustomerGuid = CustomerGuid,
@Amount = Amount,
@AmountFilled = AmountFilled,
@AssetId = AssetId,
@QuoteAssetId = QuoteAssetId,
@QuotePrice = QuotePrice,
@Total = Total,
@TotalLeft = TotalLeft
from dbo.[vOrder] WITH (HOLDLOCK, ROWLOCK)
where OrderId = @OrderId
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Order not found', 16, 1)
return 3
end
set @AmountLeft = @Amount - ISNULL(@AmountFilled, 0)
if (@OrderTypeId = 'buy')
begin
--declare @Released decimal(18, 8)
--select @Released = coalesce(SUM(Total), 0)
--from dbo.[vOrder]
--where OrderId in (select FillerId from dbo.Filler where OrderId = @OrderId)
--or OrderId in (select OrderId from dbo.Filler where FillerId = @OrderId)
declare @Released decimal(18, 8)
select @Released = Amount
from dbo.Trade t join dbo.JournalEntry j on t.EntryId = j.EntryId
where SourceOrderId = @OrderId
set @Released = ISNULL(@Released, 0)
print 'Order Type = ' + @OrderTypeId
print '@InitialAmount = ' + isnull(cast (@Amount as nvarchar), 'NULL') + ' ' + @AssetId
print '@AmountFilled = ' + isnull(cast (@AmountFilled as nvarchar), 'NULL') + ' ' + @AssetId
print '@AmountLeft = ' + isnull(cast (@AmountLeft as nvarchar), 'NULL')
print ''
print '@InitialBlocked = ' + isnull(cast (@Total as nvarchar), 'NULL') + ' ' + @QuoteAssetId
print '@Released = ' + cast (@Released as nvarchar) + ' ' + @QuoteAssetId
print '@CurrentBlocked = ' + isnull(cast (@TotalLeft as nvarchar), 'NULL') + ' ' + @QuoteAssetId
print ''
set @Explanation = N'Revoke order process. Reverse blocked quote amount' --+ 'reverse' --+ cast(@EntryId as nvarchar)
DECLARE @RC int
declare @Date datetimeoffset
set @Date = sysdatetimeoffset()
set @AssetReserveAccountId = (select AccountId from dbo.Account where CustomerGuid = @CustomerGuid and MasterAccountNo = 99931 and AssetId = @QuoteAssetId)
set @AssetAccountId = (select AccountId from dbo.Account where CustomerGuid = @CustomerGuid and MasterAccountNo = 9993 and AssetId = @QuoteAssetId)
set @EntryAmount = @Amount * @QuotePrice - @Released
print 'Order total = ' + cast (@Amount * @QuotePrice as nvarchar)
print 'Money spent to buy asset = ' + cast (@Released as nvarchar)
print 'Money to refund to buyer = ' + cast (@EntryAmount as nvarchar)
print '@Amount = ' + cast (@Amount as nvarchar)
print '@QuotePrice = ' + cast (@QuotePrice as nvarchar)
--rollback
--return 111
EXECUTE @RC = [dbo].[AddJournalEntry]
@Date
,@AssetReserveAccountId
,@AssetAccountId
,@EntryAmount
,@QuoteAssetId
,@Explanation
,'revoke'
,@OrderId
,@MasterEntryId
,@NewEntryId OUTPUT
if @@ERROR <> 0 or @RC <> 0
begin
rollback
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
if (@OrderTypeId = 'sell')
begin
print 'sell order'
set @Explanation = N'Revoke order process. Reverse blocked amount journal entry' --+ 'რევერსი' --+ cast(@EntryId as nvarchar)
set @Date = sysdatetimeoffset()
set @AssetReserveAccountId = (select AccountId from dbo.Account where CustomerGuid = @CustomerGuid and MasterAccountNo = 99931 and AssetId = @AssetId)
set @AssetAccountId = (select AccountId from dbo.Account where CustomerGuid = @CustomerGuid and MasterAccountNo = 9993 and AssetId = @AssetId)
set @EntryAmount = @AmountLeft
print '@EntryAmount = ' + isnull(cast (@EntryAmount as nvarchar), 'NULL')
EXECUTE @RC = [dbo].[AddJournalEntry]
@Date
,@AssetReserveAccountId
,@AssetAccountId
,@EntryAmount
,@AssetId
,@Explanation
,'revoke'
,@OrderId
,@MasterEntryId
,@NewEntryId OUTPUT
if @@ERROR <> 0 or @RC <> 0
begin
rollback
raiserror ('Revoke order process. Can not add reverse blocked amount journal entry', 16, 1)
return 5
end
end
-- STEP 4
update dbo.[Order]
set OrderStatusId = 30
where OrderId = @OrderId
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Can not set order status to REVOKED', 16, 1)
return 2
end
commit tran
return 0
END
go
Custom error I am getting is defined in query called AddJournalEntry我得到的自定义错误是在名为AddJournalEntry的查询中定义的
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[AddJournalEntry]
@Date datetimeoffset,
@Debit int,
@Credit int,
@Amount decimal(18, 8),
@AssetId nvarchar(50),
@Explanation nvarchar(100),
@EntryType nvarchar(50),
@OrderId int = null,
@MasterEntryId int = null,
@EntryId int OUTPUT
AS
declare @DebitBalance decimal(18, 8)
declare @DebitAccountAssetId nvarchar(10)
declare @CreditAccountAssetId nvarchar(10)
declare @CreditBalance decimal(18, 8)
declare @ToIncrease nvarchar(100)
declare @DebitAccountTitle nvarchar(500)
declare @CreditAccountTitle nvarchar(500)
declare @Error nvarchar(500)
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET XACT_ABORT ON;
SET NOCOUNT ON;
print ''
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print 'Start AddJournalEntry procedure'
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print ''
begin tran
-- STEP 1
print '@Debit = ' + isnull(cast(@Debit as nvarchar), 'NULL')
print '@Credit = ' + isnull(cast(@Credit as nvarchar), 'NULL')
print '@AssetId = ' + cast(@AssetId as nvarchar(50))
print '@Amount = ' + cast(@Amount as nvarchar(50))
update dbo.Account
set Debit = Debit + @Amount, LastTransactionDate = SYSDATETIMEOFFSET()
where AccountId = @Debit
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Can not update debit account balance', 16, 1)
return 2
end
update dbo.Account
set Credit = Credit + @Amount, LastTransactionDate = SYSDATETIMEOFFSET()
where AccountId = @Credit
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Can not find or update credit account balance', 16, 1)
return 3
end
select
@DebitBalance = Balance,
@ToIncrease = ToIncrease,
@DebitAccountTitle = AccountFullTitle
from dbo.vAccount
where AccountId = @Debit and AssetId = @AssetId
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Can not find debit account', 16, 1)
return 4
end
print 'New Debit Balance = ' + cast(@DebitBalance as nvarchar(50))
if (@DebitBalance < 0 and @ToIncrease = 'debit') or (@DebitBalance > 0 and @ToIncrease = 'credit')
begin
rollback
set @Error = 'Debit account balance can not be less than 0. ' + @DebitAccountTitle
raiserror (@Error, 16, 1)
return 5
end
-- STEP 4
select
@CreditBalance = Balance,
@ToIncrease = ToIncrease,
@CreditAccountTitle = AccountFullTitle
from dbo.vAccount
where AccountId = @Credit and AssetId = @AssetId
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
rollback
raiserror ('Can not find credit account', 16, 1)
return 55
end
if (@CreditBalance > 0 and @ToIncrease = 'credit') or (@CreditBalance < 0 and @ToIncrease = 'debit')
begin
rollback
set @Error = 'Credit account balance can not be less than 0. ' + @CreditAccountTitle
raiserror ( @Error, 16, 1)
return 56
end
-- STEP 4
insert dbo.JournalEntry
select SYSDATETIMEOFFSET(), @Debit, @Credit, @Amount, @AssetId, @Explanation, @DebitBalance, @CreditBalance, @OrderId, @MasterEntryId, @EntryType, NEWID()
if @@ERROR <> 0
begin
rollback
raiserror ('Can not insert entry record', 16, 1)
return 1
end
commit tran
set @EntryId = SCOPE_IDENTITY()
return 0
END
go
You are executing multiple ROLLBACK
commands when you should only execute it once.当您应该只执行一次时,您正在执行多个
ROLLBACK
命令。 A rollback will lower the transaction count from any amount higher than 0 directly to 0, so if you execute 3 BEGIN TRANSACTION
, your @@TRANCOUNT
is 3 and a rollback will set it to 0. The problem is that you are executing a rollback inside the called SP (the nested one) and again after the SP returns.回滚会将事务计数从高于 0 的任何数量直接降低到 0,因此如果执行 3
BEGIN TRANSACTION
,您的@@TRANCOUNT
为 3,回滚会将其设置为 0。问题是您正在执行回滚内部被调用的 SP(嵌套的)并在 SP 返回后再次调用。
You can see the problem with this example:你可以看到这个例子的问题:
BEGIN TRANSACTION
SELECT @@TRANCOUNT -- 1
BEGIN TRANSACTION
SELECT @@TRANCOUNT -- 2
ROLLBACK
SELECT @@TRANCOUNT -- 0
ROLLBACK -- The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
And this is the failing execution route from your SP:这是来自您的 SP 的失败执行路线:
CREATE PROCEDURE [dbo].[RevokeOrder]
@OrderId int = null
AS
begin tran -- Create a transaction here (TRANCOUNT = 1)
if (...)
begin
EXECUTE @RC = [dbo].[AddJournalEntry] -- Executes a rollback inside
if @@ERROR <> 0 or @RC <> 0
begin
rollback -- When the execution reaches this rollback, TRANCOUNT is 0 and the rollback fails
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
END
And the SP being called: SP被称为:
CREATE PROCEDURE [dbo].[AddJournalEntry]
AS
BEGIN
begin tran -- TRANCOUNT = 2
if (@DebitBalance < 0 and @ToIncrease = 'debit') or (@DebitBalance > 0 and @ToIncrease = 'credit')
begin
rollback -- Undoes all changes from the start of the first BEGIN TRAN and sets TRANCOUNT to 0
set @Error = 'Debit account balance can not be less than 0. ' + @DebitAccountTitle
raiserror (@Error, 16, 1)
return 5
end
END
I'd recommend using TRY/CATCH blocks and doing the ROLLBACK
on the CATCH
.我建议使用 TRY/CATCH 块并在
CATCH
上执行ROLLBACK
。 This would be like the following:这将如下所示:
CREATE PROCEDURE [dbo].[RevokeOrder]
@OrderId int = null
AS
BEGIN TRY
begin tran
if (...)
begin
EXECUTE @RC = [dbo].[AddJournalEntry]
if @@ERROR <> 0 or @RC <> 0
begin
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
COMMIT
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 -- Might want to check XACT State also
ROLLBACK
-- Additional logging/fixing stuff
END CATCH
END
For detailed explanation on SQL Server error handling, check this post .有关 SQL 服务器错误处理的详细说明,请查看此帖子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.