0
我有兩個表定義爲錯誤和抓住或檢查現有的更好嗎?
CREATE TABLE [dbo].[Foo](
FOO_GUID uniqueidentifier NOT NULL PRIMARY KEY CLUSTERED,
SECOND_COLUMN nvarchar(10) NOT NULL,
THIRD_COLUMN nvarchar(10) NOT NULL)
CREATE TABLE [dbo].[FooChanged](
[FooGuid] uniqueidentifier NOT NULL PRIMARY KEY CLUSTERED,
[IsNewRecord] bit NOT NULL)
和觸發
CREATE TRIGGER dbo.[trg_FooChanged]
ON [dbo].[Foo]
AFTER INSERT,UPDATE
NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
DECLARE @isNewRecord as bit;
IF EXISTS(SELECT * FROM DELETED)
BEGIN
--We only want to make a record if the guid or one other column in Foo changed.
IF NOT(UPDATE(FOO_GUID) OR UPDATE(SECOND_COLUMN))
RETURN;
SET @isNewRecord = 0
END
ELSE
SET @isNewRecord = 1;
insert into FooChanged(FooGuid, IsNewRecord) SELECT FOO_GUID, @isNewRecord from INSERTED
END
下面的簡單的測試腳本與一個主鍵約束衝突的最後一批(預期)
INSERT INTO [dbo].[Foo] ([FOO_GUID],[SECOND_COLUMN],[THIRD_COLUMN]) VALUES (cast(0x1 as uniqueidentifier), '1', '1')
GO
INSERT INTO [dbo].[Foo]([FOO_GUID],[SECOND_COLUMN],[THIRD_COLUMN]) VALUES (cast(0x2 as uniqueidentifier), '2', '2')
GO
UPDATE Foo SET THIRD_COLUMN = '1a' WHERE FOO_GUID = cast(0x1 as uniqueidentifier)
GO
UPDATE Foo SET SECOND_COLUMN = '1a' WHERE FOO_GUID = cast(0x1 as uniqueidentifier)
GO
失敗
我的問題是,這是「正確」的方式,不要讓錯誤傳播給用戶,也不會搞亂用戶可能擁有的任何當前事務(w可能的設置如XACT_ABORT ON
)。
兩個選項我看到的是插入
declare @guid uniqueidentifier
select @guid = FOO_GUID from INSERTED
BEGIN TRANSACTION
if NOT EXISTS(select * from FooChanged WITH (UPDLOCK, HOLDLOCK) where FooGuid = @guid)
insert into FooChanged(FooGuid, IsNewRecord) SELECT @guid, @isNewRecord from INSERTED
COMMIT TRANSACTION
前兩種檢查,但我需要鎖在桌子上,以防止任何種族條件,我認爲將導致忙表
或性能問題捕獲錯誤在一個try/catch
BEGIN TRY
insert into FooChanged(FooGuid, IsNewRecord) SELECT @guid, @isNewRecord from INSERTED
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
if(ERROR_NUMBER() != 2627)
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH
但我擔心代碼XACT_ABORT事務內部運行得到它的XACT_STATE
與。
什麼是正確的使用方法?
我知道在C#中這是真的,但我不知道是否相同的規則適用於SQL。謝謝! –
做了一些測試後,我發現我總是得到'在觸發器執行過程中出現錯誤。該批處理已被中止,並且用戶事務(如果有的話)已被回滾。「所以catch方法不是一個選項。在詢問之前應該多測試一下。 –