C# Transaction 事务处理 -环境事务
一、TransactionScope 环境事务
1 static async Task TransactionScopeAsync() 2 { 3 using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) 4 { 5 Transaction.Current.TransactionCompleted += OnTransactionCompleted; 6 7 Utilities.DisplayTransactionInformation("Ambient TX created", 8 Transaction.Current.TransactionInformation); 9 10 var s1 = new Student 11 { 12 FirstName = "Angela", 13 LastName = "Nagel", 14 Company = "Kantine M101" 15 }; 16 var db = new StudentData(); 17 await db.AddStudentAsync(s1); 18 19 if (!Utilities.AbortTx()) 20 scope.Complete(); 21 else 22 Console.WriteLine("transaction will be aborted"); 23 24 } // scope.Dispose() 25 26 }
二、嵌套事务
1 static void NestedScopes() 2 { 3 using (var scope = new TransactionScope()) 4 { 5 Transaction.Current.TransactionCompleted += OnTransactionCompleted; 6 7 Utilities.DisplayTransactionInformation("Ambient TX created", 8 Transaction.Current.TransactionInformation); 9 10 using (var scope2 = 11 new TransactionScope(TransactionScopeOption.RequiresNew)) 12 { 13 Transaction.Current.TransactionCompleted += OnTransactionCompleted; 14 15 Utilities.DisplayTransactionInformation( 16 "Inner Transaction Scope", 17 Transaction.Current.TransactionInformation); 18 19 scope2.Complete(); 20 } 21 scope.Complete(); 22 } 23 24 }
事务完成代码
1 static void OnTransactionCompleted(object sender, TransactionEventArgs e) 2 { 3 Utilities.DisplayTransactionInformation("TX completed", 4 e.Transaction.TransactionInformation); 5 }
你可能不知道这一点,在 .NET Framework 4.5.0 版本中包含有一个关于 System.Transactions.TransactionScope 在与 async/await 一起工作时会产生的一个严重的 bug 。由于这个错误,TransactionScope 不能在异步代码中正常操作,它可能更改事务的线程上下文,导致在处理事务作用域时抛出异常。
这是一个很大的问题,因为它使得涉及事务的异步代码极易出错。
好消息是,在 .NET Framework 4.5.1 版本中,微软发布了这个 "异步连接" 错误的修复程序。作为开发者的我们需要明确的做到以下两点:
- 如果说你在 TransactionScope 代码中使用 async/await,你需要将框架升级到 .NET 4.5.1 或以上版本。
- 在有包装异步代码的 TransactionScope 的构造函数中指定
TransactionScopeAsyncFlowOption.Enabled .
TransactionScopeAsyncFlowOption
在 .NET 4.5.1中,TransactionScope 有一个名为 TransactionScopeAsyncFlowOption 的新枚举,可以在构造函数中提供。 您必须通过指定,明确地选择跨线程连续的事务流,如下:
1 using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) 2 { 3 await SomeMethodInTheCallStackAsync() 4 .ConfigureAwait(false); 5 6 tx.Complete(); 7 }
你可能很好奇,默认的 TransactionScopeAsyncFlowOption 是 Suppress(阻止的),因为微软想避免破坏 .NET 4.5.0 版本中代码库中行为。
最后
使用 TransactionScope 结合 async / await 时,你应该更新所有使用 TransactionScope 的代码路径以启用 TransactionScopeAsyncFlowOption.Enabled 。 这样才能使事务能够正确地流入异步代码,防止在TransactionScope下使用时业务逻辑不正常。
鹰击长空,鱼翔浅底