在維護一個非常舊的項目時,由於該項目版本已經非常老了,而且在客戶現場運行的非常穩定,更要命的是本人目前沒有找到該項目的代碼,為了處理一個新的需求而且還不能修改程序代碼,於是決定從數據庫入手,畢竟該項目數據庫的腳本還是可以操作的,那就在數據流的必經之路上攔截數據處理業務就是了,於是決定在一張業務表上加一個觸發器,關於觸發器的基礎這里就不多說了,網上一搜一大堆,其實就是一張表的數據行被操作以后會針對被操作的數據行執行一段存儲過程腳本,只不過這個存儲過程比較特殊罷了,是專門偵聽對表的操作然后由系統調用的而已……
只要用觸發器肯定會操作inserted和deleted兩張表,大家切記在寫t-sql業務操作之前一定要判斷這兩張虛表中是不是有數據,如果不判斷直接往下執行就有可能報“在觸發器執行過程中引發了錯誤,批處理已中止,用戶事務(如果有)已回滾”的錯誤,本人就吃了一個這樣的虧;觸發器剛加上前幾天運行的挺正常,等過幾天發現有些針對這張業務表執行其它業務操作一執行就報前面所說的錯誤,查了n久發現業務操作中執行了一個update語句,而這個update語句的where條件過濾后其實一條符合where條件的數據都沒有,這樣就導致執行觸發器的時候 deleted和inserted兩張虛表中是沒有數據的,再操作下去就報錯了,觸發器一報錯正常的原來好用業務也報錯了……
解決方法很簡單,在觸發器的結尾加一個結束標簽TheEnd,然后在觸發器入口判斷兩張虛表(inserted和deleted)是否有數據,如果都沒有數據直接跳轉到結束標簽TheEnd處不處理就是了,只有有數據的時候才執行業務處理,大概代碼如下,看紅色加粗部分:
create trigger [dbo].[Tgr_MyTable_InsertUpdate] --觸發器名 on [dbo].[MyTable] --MyTable是實際業務表名 for insert,update AS declare @IsUpdate bit; declare @IsInsert bit; declare @IsDelete bit; set @IsDelete=-1; set @IsInsert=-1; set @IsUpdate=-1; --這個判斷很關鍵,如果沒有數據那就別處理了,直接跳轉到末尾 if not exists (select 1 from inserted) and not exists (select 1 from deleted) begin goto TheEnd; --TheEnd是腳本結尾處的結束標簽 end else if exists (select 1 from inserted) and exists (select 1 from deleted) begin set @IsUpdate=1; -- 如果兩張虛表都有數據表示執行的是update操作 end else if exists (select 1 from inserted) and not exists (select 1 from deleted) begin set @IsInsert=1; -- 只有inserted有數據表示是執行insert語句觸發的 end else begin set @IsDelete=1; end begin try declare @newValue varchar(100); declare @oldValue varchar(100); if @IsInsert=1 or @IsUpdate=1 begin --獲取新修改的Name字段 SELECT @tempValue = Name FROM inserted; begin if @IsUpdate=1 or @IsDelete=1 begin --獲取修改或刪除前的Name字段 SELECT @oldValue = Name FROM deleted; end -- 其它業務處理...... end try begin catch begin try declare @Error varchar(200); set @Error='TgrError:'+cast(ERROR_LINE() as varchar)+'_' +isnull(ERROR_MESSAGE(),''); -- 將@Error的值可以記錄到一個執行的日志表中 end try begin catch end catch end catch TheEnd:
就是這么簡單,以上排查問題結果分享給其它小伙伴,希望大家別再走我的彎路