我遇到了一个与 SQL 相关的问题,现在让我很生气:p。这是我的设置:
我有 2 个存储过程:
父存储过程被调用GenerateAnnualPenalty
。
GenerateAnnualPenalty
其中有一个 SELECT CURSOR,它遍历一系列名为 的对象Properties
,并且对于每个Property
,它确定是否Penalty
需要应用 a 。这存储在一个名为 的布尔变量中@ApplyPenalty
,以及它的0
or 或1
。此外,在GenerateAnnualPenalty
.
其次,对于每个Property
迭代GenerateAnnualPenalty
,它调用一个名为的子存储过程GenerateAnnualPenaltyForProperty
。@ApplyPenalty
作为输入传递给GenerateAnnualPenaltyForProperty
。GenerateAnnualPenaltyForProperty
确实使用 SQL 事务(提交/回滚)。
我在名为 的表中输入条目DebugLog
,以标记代码中是否已到达特定点。
这是孩子的骨架GenerateAnnualPenaltyForProperty
:
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
DECLARE @TRANSACTION_NAME varchar(50)
SET @TRANSACTION_NAME = 'GenerateAnnualPenaltyForProperty'
BEGIN TRANSACTION @TRANSACTION_NAME
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
COMMIT TRANSACTION @TRANSACTION_NAME
RETURN 0
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION @TRANSACTION_NAME
RETURN -1
END CATCH
问题(简介):
假设以这个特定的顺序GenerateAnnualPenalty
迭代 4 Properties
(利用了这个问题):
要迭代的第一个属性:@PROPERTY_ID = 1
要迭代的第二个属性:@PROPERTY_ID = 2
要迭代的第三个属性:@PROPERTY_ID = 3
要迭代的第四个属性:@PROPERTY_ID = 4
假设对于属性 1、3 和 4,ApplyPenalty = 1
,而对于属性 2,ApplyPenalty = 0
问题(主要症结):
当GenerateAnnualPenaltyForProperty
调用属性 1 时,一切都很好:我在表中看到了检查点 1 和检查点 2 条目DebugLog
。
当GenerateAnnualPenaltyForProperty
调用属性 2 时,一切都恢复正常:我在表中同时看到检查点 1 和检查点 2 条目DebugLog
。
当GenerateAnnualPenaltyForProperty
调用属性 3 时,会出现不正确的情况:我只看到表中的检查点 1 条目DebugLog
,而“检查点 2”条目也应该是可见的!
当GenerateAnnualPenaltyForProperty
调用属性 4 时,它再次正确:我再次在表中看到检查点 1 和检查点 2 条目DebugLog
。
因此,问题仅发生在 的 属性中ApplyPenalty = 1
,前提是在之前的迭代中,ApplyPenalty = 0
。在这种情况下,带有的属性ApplyPenalty = 1
会被视为ApplyPenalty = 0
禁用 SQL 事务代码可以解决问题,但为什么?:
如果我禁用所有GenerateAnnualPenaltyForProperty
与 SQL 事务相关的代码,一切正常!纠正了上述有问题的情况。这是一个框架GenerateAnnualPenaltyForProperty
,其中已取出 SQL 事务代码,它适用于:
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
RETURN 0
END TRY
BEGIN CATCH
RETURN -1
END CATCH
问题(???):
为什么会出现这种行为?为什么当我使用 SQL Transaction commit/rollback intoGenerateAnnualPenaltyForProperty
时,存储过程不适用于有问题的情况?
实际代码:
如果有人希望查看子存储过程的完整代码,则可在此处获得:https ://gist.github.com/anonymous/5214236