[英]Why does this SQL Server transaction always fail and how to fix the stored procedure structure?
我在存储过程中遇到麻烦,而事务总是失败。 我认为这是由于IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId)
或结构化代码的方式,但是我不确定如何修复存储过程,因此事务不会总是失败。 当我删除所有事务代码并在存储过程中没有事务的情况下执行相同的活动时,它将起作用。 所有更新和/或插入均成功。
CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update]
(
@BaseTableId bigint,
@BaseTableTypeId bigint,
@Alias nvarchar(max),
@TargetTableNonPkItemId bigint,
@OtherField nvarchar(max) = NULL
)
AS
-- NOTE: There is a problem with enabling tractions on this, the trans always fails
-- with the current structure, seemingly because of the SELECT 1 FROM TARGETTABLE
BEGIN
BEGIN TRAN
UPDATE BaseTable
SET
Alias = @Alias,
BaseTableTypeId = @BaseTableTypeId,
UpdatedOn = GETUTCDATE()
WHERE BaseTableId = @BaseTableId
IF @@ERROR <> 0
BEGIN
RAISERROR('Error updating BaseTable', 16, 1)
ROLLBACK TRAN
RETURN
END
IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId)
UPDATE TargetTable
SET
TargetTableNonPkItemId = @TargetTableNonPkItemId,
OtherField = @OtherField
WHERE BaseTableId = @BaseTableId
IF @@ERROR <> 0
BEGIN
RAISERROR('Error updating TargetTable', 16, 1)
ROLLBACK TRAN
RETURN
END
ELSE
INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField)
VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField)
IF @@ERROR <> 0
BEGIN
RAISERROR('Error inserting TargetTable', 16, 1)
ROLLBACK TRAN
RETURN
END
COMMIT TRAN
END
您需要包装IF
。 您的代码中发生的事情是您期望这样的事情
IF EXISTS
{
UPDATE
RAISE ERROR IF BAD
}
ELSE
{
INSERT
RAISE ERROR IF BAD
}
但是相反,你最终会得到这个
IF EXISTS
UPDATE
IF ERROR
RAISE ERROR
ELSE
INSERT
IF ERROR
RAISE ERROR
因此,代码如下所示:
CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update]
(
@BaseTableId bigint,
@BaseTableTypeId bigint,
@Alias nvarchar(max),
@TargetTableNonPkItemId bigint,
@OtherField nvarchar(max) = NULL
)
AS
-- NOTE: There is a problem with enabling tractions on this, the trans always fails
-- with the current structure, seemingly because of the SELECT 1 FROM TARGETTABLE
BEGIN
BEGIN TRAN
UPDATE BaseTable
SET
Alias = @Alias,
BaseTableTypeId = @BaseTableTypeId,
UpdatedOn = GETUTCDATE()
WHERE BaseTableId = @BaseTableId
IF @@ERROR <> 0
BEGIN
RAISERROR('Error updating BaseTable', 16, 1)
ROLLBACK TRAN
RETURN
END
IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId)
BEGIN
UPDATE TargetTable
SET
TargetTableNonPkItemId = @TargetTableNonPkItemId,
OtherField = @OtherField
WHERE BaseTableId = @BaseTableId
IF @@ERROR <> 0
BEGIN
RAISERROR('Error updating TargetTable', 16, 1)
ROLLBACK TRAN
RETURN
END
END
ELSE
BEGIN
INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField)
VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField)
IF @@ERROR <> 0
BEGIN
RAISERROR('Error inserting TargetTable', 16, 1)
ROLLBACK TRAN
RETURN
END
END
COMMIT TRAN
END
您应该在IF之后和ELSE之后添加BEGIN / END块,因为这些块中有多个语句。
我更喜欢使用TRY CATCH进行错误处理。 下面的示例将给出更有用的错误消息。
CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update]
( @BaseTableId bigint
, @BaseTableTypeId bigint
, @Alias nvarchar(max)
, @TargetTableNonPkItemId bigint
, @OtherField nvarchar(max) = NULL )
AS
BEGIN TRY
BEGIN TRAN
UPDATE BaseTable
SET Alias = @Alias
, BaseTableTypeId = @BaseTableTypeId
, UpdatedOn = GETUTCDATE()
WHERE BaseTableId = @BaseTableId
IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId)
UPDATE TargetTable
SET TargetTableNonPkItemId = @TargetTableNonPkItemId
, OtherField = @OtherField
WHERE BaseTableId = @BaseTableId
ELSE
INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField)
VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField)
IF @@TRANCOUNT > 0
BEGIN
COMMIT TRAN
END
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRAN
END
END CATCH
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.