对TransactionScope的Complete方法的误用
由于找不到更好的方法,项目也没采用任何的第三方框架(如NHibernate),所以在业务层的事务处理部分我一直用TransactionScope这个东东来管理业务事务,微软把它翻译为范围事务,用它可以实现范围内的隐式事务,具体的使用方法本文就不多讲了,可以参看MSDN:http://msdn.microsoft.com/zh-cn/library/ms172152.aspx
今天我遇到一个问题,在方法A中引入TransactionScope,A中调用方法B,B中也引入了TransactionScope(TransactionScope是可以嵌套的哦),我的代码好多都是这么写的:
这样如果B中有方法执行不正确,就没有执行complete,这样,在被调用函数内部,直接终止了该环境事务,如果下面的代码中还有引用TransactionScope的,就会抛出“事务已终止”的异常。
我一直以为complete应该放在“正确的业务逻辑”里面,如果程序执行不正确就不要执行complete,它会自动回滚。我现在知道我的想法是灰常错误的,它是会回滚,它直接终止了都。以下是MSDN的解释:
当您对范围中的所有操作都已成功完成感到满意时,应该仅调用此方法一次,以通知事务管理器所有资源上的状态都是一致的,并且可以提交该事务。将该调用作为 using 块中的最后一个语句是很好的做法。
有关如何使用此方法的更多信息,请参见 使用事务范围实现隐式事务 主题。
未能调用此方法将中止事务,因为事务管理器将此解释为系统故障或在事务范围中引发了异常。但是还应该注意,调用此方法并不保证事务的提交。它只是一种将状态通知给事务管理器的方式。在调用此方法之后,就不能再通过 Current 属性访问环境事务,尝试这样做将导致引发异常。
如果 TransactionScope 对象创建事务,则资源管理器之间的实际提交工作发生在 End Using 语句处。如果它未创建事务,则在每当 CommittableTransaction 对象的所有者调用 Commit 时发生提交。届时事务管理器将调用资源管理器,并根据是否在 TransactionScope 对象上调用了此方法来通知它们进行提交或回滚。
看这句“未能调用此方法将中止事务”,这也就是说,如果你不调用complete方法,事务直接终止,“因为事务管理器将此解释为系统故障或在事务范围中引发了异常”,所以现在我理解透彻了TransactionScope,它能保证你在它的生命周期内的隐式事务,无论你做什么数据库操作,它都会为你把这些操作全组织到一个环境事务中,如果你哪个环节出现问题,整个事务会隐式的回滚,complete不是告诉事务管理器马上开始提交,而只是通知事务管理器我的操作状态完成了,我以前把它当dbtransaction了,执行成功才submit,不成功rollback,而complete只是说“我的活干完了,你可以提交了”,如果你不在它的生命周期内调用这个方法,事务会中止,此时就像我上面写的方法B,当你再次尝试(using一个new TransactionScope)的时候,你会碰到“事务已终止”的错误。所以,我以后的代码修改成这样:
希望大家碰到类似问题的,可以参考一下。