在维护一个非常旧的项目时,由于该项目版本已经非常老了,而且在客户现场运行的非常稳定,更要命的是本人目前没有找到该项目的代码,为了处理一个新的需求而且还不能修改程序代码,于是决定从数据库入手,毕竟该项目数据库的脚本还是可以操作的,那就在数据流的必经之路上拦截数据处理业务就是了,于是决定在一张业务表上加一个触发器,关于触发器的基础这里就不多说了,网上一搜一大堆,其实就是一张表的数据行被操作以后会针对被操作的数据行执行一段存储过程脚本,只不过这个存储过程比较特殊罢了,是专门侦听对表的操作然后由系统调用的而已……
只要用触发器肯定会操作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:
就是这么简单,以上排查问题结果分享给其它小伙伴,希望大家别再走我的弯路
原文地址:https://www.cnblogs.com/Taburensheng/p/9706102.html