.NET服务端故障转移后TransactionScope状态及事务选型咨询
故障转移场景下的.NET事务问题解答
背景
两台服务器分别运行.NET代码和数据库,预期故障转移对象为运行.NET代码的服务器,存在以下疑问:
问题1:服务端故障转移后,TransactionScope是否仍在运行?数据库如何自动回滚变更?
- 服务端故障转移后,原.NET进程直接终止,TransactionScope会立即停止运行——它是进程内的事务管理对象,进程挂了就不存在了。
- 数据库自动回滚逻辑:数据库会实时检测连接状态,一旦发现与原.NET服务器的连接中断,且该连接上的事务未提交(未调用
Complete()),就会自动回滚所有未提交的变更。另外你设置的60秒事务超时,也会触发数据库层面的超时回滚,形成双重保障。
问题2:需确保服务器故障时能释放锁,为保证代码整洁,应选择TransactionScope还是BeginTransaction?
- 优先选择TransactionScope:
- 锁释放保障:不管是服务器故障、代码抛出异常还是触发超时,只要没调用
Complete(),TransactionScope的using块会自动清理事务,数据库同步释放相关锁;就算进程直接挂掉,数据库检测到连接中断后也会立刻释放锁,不会出现锁长期占用的情况。 - 代码整洁性:TransactionScope的using语法天然实现了事务的自动管理,无需手动编写回滚逻辑,和你现有代码风格一致,能保持代码简洁利落。
- 锁释放保障:不管是服务器故障、代码抛出异常还是触发超时,只要没调用
- 对比BeginTransaction:它需要手动管理事务的提交和回滚分支,代码冗余度高,还容易因遗漏处理导致锁泄漏,完全没必要选。
现有代码
using (var context = DbContextCreator.Create()) { var transactionOptions = new TransactionOptions { Timeout = TransactionManager.DefaultTimeout }; // 60 seconds. using (var dbContextTransaction = new TransactionScope(TransactionScopeOption.Required, transactionOptions)) { try { context.Database.ExecuteSqlCommand("SELECT TOP 1 Id FROM SRE.ActionHistory WITH (TABLOCKX, HOLDLOCK)"); bool isDuplicated = context.ActionHistory .Any(x => x.StatusId == (int)eActionHistoryStatus.Pending && x.ActionId == (int)Action && x.DateTime >= timeToCheck && x.CustomerId == Customer.Id); if (!isDuplicated) { context.ActionHistory.Add(actionHistory); context.SaveChanges(); dbContextTransaction.Complete(); return actionHistory; } throw new BizException(BizErrorCodes.NotAllowedToDoAction); } catch (Exception ex) { // It will roll back automatically if the Complete() method isn't invoked or the timeout takes longer than the specified timeout. throw; } } } }
内容的提问来源于stack exchange,提问作者DPTP
相关产品推荐
相关产品推荐

