MS SQL 2K 触发器与.Net程序保证事务完整性

daemonking 2005-06-07 10:52:08

这几天做了一个触发器,不要拿棍子抡我,就是要求要做一个,怎么了?不成啊,我也知道触发器不好,最好不用,但是如果没有用处,放在DB中还有什么意义呢?存在就是合理的。
触发器的作用是判断某个表(假设为T)的某一列(假设为A)在一定的记录范围内不能够有重复值,如何处理呢?肯定是要写For Update和For Insert的触发器了(废话),原本的做法是(下面的SQL都是For Insert触发器中的内容,For Update的触发器内容大同小异,就不多说了):
......
判断有重复
BEGIN
RAISERROR('The Column A can not be duplicated', 1, 1);
ROLLBACK;
RETURN;
END
......
想法是,如果出现重复了,通过SQL Server的函数RAISERROR把错误报出来,并回滚事务,使得事务能够保持,但是因为程序中的代码是这样写的:
......
try{
tran = da.InsertCommand.Connection.BeginTransaction();
//ds.Tables[0]有多行Insert记录
da.Update(ds.Tables[0]);
tran.Commit();
}
catch (Exception ee){
tran.Rollback();
}
......

结果,最终的效果是如果第一条插入的是重复记录,但是因为For Insert是在插入完以后进行的,所以,即使在触发器中RAISERROR,并且回滚了事务,但是在C#的程序中,依然会执行tran.Commit(),将Insert操作提交,保存进了数据库,进行了持久化,而不是进入catch部分,执行tran.Rollback(),怎么办??
如何让触发器中的RAISERROR报的错能够返回到应用程序呢?联想到其他的会进入catch的错误都是类似
“服务器: 消息 XXX,级别 XX,状态 X,行 X”
有理由相信,RAISERROR还是能够返回错误给应用程序,以便出错时进入catch模块,怎么做呢?在查询分析器中测试触发器的时候发现,RAISERROR报出来的信息就是写的那句话“The Column A can not be duplicated”,而没有“服务器......”这些的,也就是说,现在触发器RAISERROR出来的并不是C#认可的错误,更确切的说,这只是一个消息!!。如果能够让RAISERROR报出来的错误类似于这种形式,就可以让应用程序捕捉到,从而保证事务的完整,那么如何解决呢?
查看Transaction-SQL的帮助文件,发现,其实,类似“服务器: 消息 XXX,级别 XX,状态 X,行 X”这样子的错误,程序员使用sp_addmessage可以自行添加,添加一个:
sp_addmessage 80001,
18,
'The ATTR_NAME column can Not be DUPLICATE!',
'us_english',
'true'
然后,修改触发器:
RAISERROR(80001, 18, 1);
RETURN;
那么为什么ROLLBACK也被去掉了?因为外部的程序控制了事务,没有必要触发器内不再去控制,多此一举
至此,运行程序进行测试,OK,没有问题,搞定
收获是什么呢?
第一,思考的方法,当看到RAISERROR返回的“错误”不能够被catch到,怎么办?看到标准的SQL Server返回错误是可以被catch的,这个时候想到,让RAISERROR返回的错误类似于SQL Server的那些错误是不是就可以了?结果证明,是对的。
第二,RAISERROR('error message', 1, 1)踢出来的不是错误,而是一个hint,一个提示信息而已,是不能够被catch到的
...全文
195 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧