/// <summary> /// 构造方法 /// </summary> /// <param name="option">描述与此事务范围关联的事务要求</param> /// <param name="timeout">在该时间间隔之后,事务范围将超时并中止此事务。 /// 非根级事务环境中,仅当option为RequiresNew时有效。 /// 特:rootScope是Suppress时,根级事务环境就不是rootScope。 /// </param> public MyTransactionScope(System.Transactions.TransactionScopeOption option, TimeSpan timeout) { this.scopeOption = option; this.timeSpan = timeout; /********************************************************************* ** rootScope的Option可能是:Required,RequiresNew,Suppress ** currentScope不是rootScope的情况下,Option可能是:RequiresNew,Suppress ** ** 备注:因为Root和Current是ThreadStatic,所以处理时不用lock. *********************************************************************/ if (rootScope == null) //设置根级事务环境 { this.scopeStack = null; rootScope = this; currentScope = this; } else //更新当前事务环境 { //两种情况不更新当前事务环境currentScope: // 1)向RequiresNew/Required的环境下,创建Required环境; // 2)向Suppress的环境下,创建Suppress环境。 if (option == System.Transactions.TransactionScopeOption.Required) { switch (currentScope.ScopeOption) { case System.Transactions.TransactionScopeOption.Required: case System.Transactions.TransactionScopeOption.RequiresNew: this.hostScopeID = currentScope.ScopeID; return; //不更新Current case System.Transactions.TransactionScopeOption.Suppress: default: break; } } else if (option == System.Transactions.TransactionScopeOption.Suppress) { if (currentScope.ScopeOption == System.Transactions.TransactionScopeOption.Suppress) { this.hostScopeID = currentScope.ScopeID; return; //不更新Current } } this.hostScopeID = Guid.Empty; if (currentScope != null) { //更新前,将之前的事务环境加入“事务链”. if (rootScope.scopeStack == null) { rootScope.scopeStack = new Stack <MyTransactionScope>(); } rootScope.scopeStack.Push(currentScope); } currentScope = this; } }
//嵌套事务中,在不同事务环境里对同一条记录做了更新.会在提交时发生死锁. public static void Test2(bool showLock) { Console.WriteLine("\r\n==================\r\nCalling MyTrans.Test2()"); //string connStr = Manager.GetConnStringOfOra1(); string connStr = string.Format("Data Source={0};User ID={1};Password={2};Persist Security Info=True;Pooling=true", "bhdevcomber", //Helper.GetDatasource4OraTNS("192.168.100.52", "1521", "bhdevcomber"), // "bhdata", "bhdata"); DbAccess db = new DbAccess(connStr); //确保记录存在,用于验证Update. try { db.Insert("8", "eight-0"); } catch { } try { db.Insert("9", "nine-0"); } catch { } Console.WriteLine("Last - 8:{0}", db.SelectEditTimeByCode("8")); Console.WriteLine("Last - 9:{0}", db.SelectEditTimeByCode("9")); Console.WriteLine("------------------"); try { using (MyTransactionScope scope = new MyTransactionScope()) { if (showLock) { db.Update("8", "eight-1"); Console.WriteLine("Update - 8:{0}", db.SelectEditTimeByCode("8")); } db.Update("9", "nine-1"); Console.WriteLine("Update - 9:{0}", db.SelectEditTimeByCode("9")); using (MyTransactionScope scope1 = new MyTransactionScope(TransactionScopeOption.RequiresNew)) { db.Update("8", "eight-2"); Console.WriteLine("Update in inner scope - 8:{0}", db.SelectEditTimeByCode("8")); if (showLock) { db.Update("9", "nine-2"); Console.WriteLine("Update in inner scope - 9:{0}", db.SelectEditTimeByCode("9")); } scope1.Complete(); } scope.Complete(); } } catch (Exception ex) { Console.WriteLine("Trans Error:" + ex.ToString()); } Console.WriteLine("------------------"); Console.WriteLine("Last - 8:{0}", db.SelectEditTimeByCode("8")); Console.WriteLine("Last - 9:{0}", db.SelectEditTimeByCode("9")); }
public static void Test1() { Console.WriteLine("\r\n==================\r\nCalling MyTrans.Test1()"); //string connStr = Manager.GetConnStringOfOra1(); string connStr = string.Format("Data Source={0};User ID={1};Password={2};Persist Security Info=True;Pooling=true", "bhdevcomber", //Helper.GetDatasource4OraTNS("192.168.100.52", "1521", "bhdevcomber"), // "bhdata", "bhdata"); DbAccess db = new DbAccess(connStr); Console.WriteLine("Last - 0:{0}", db.SelectCreateTimeByCode("0")); Console.WriteLine("Last - 1:{0}", db.SelectCreateTimeByCode("1")); Console.WriteLine("Last - 2:{0}", db.SelectCreateTimeByCode("2")); Console.WriteLine("Last -22:{0}", db.SelectCreateTimeByCode("22")); Console.WriteLine("Last - 3:{0}", db.SelectCreateTimeByCode("3")); Console.WriteLine("------------------"); try { bool commit; using (MyTransactionScope scope = new MyTransactionScope(new TimeSpan(0, 1, 20))) { try { db.DeleteByCode("0"); db.Insert("0", "zero"); Console.WriteLine("Insert - 0:{0}", db.SelectCreateTimeByCode("0")); //db.CreateTable(); //db.Insert("0", "zero1"); commit = true; } catch (Exception ex1) { Console.WriteLine(ex1.ToString()); commit = false; } TransactionScopeOption scopeOption1 = TransactionScopeOption.RequiresNew; TransactionScopeOption scopeOption2 = TransactionScopeOption.Suppress; #region Scope1 using (MyTransactionScope scope1 = new MyTransactionScope(scopeOption1)) { Console.WriteLine("scope1.{0}\r\n{{", scopeOption1.ToString()); bool succeed1 = false; try { Console.WriteLine("Read - 0:{0}", db.SelectCreateTimeByCode("0")); db.DeleteByCode("1"); db.Insert("1", "one"); Console.WriteLine("Insert - 1:{0}", db.SelectCreateTimeByCode("1")); db.Insert("0", "zero2"); //Console.WriteLine("Insert-0:{0}", db.SelectByCode("0")); succeed1 = true; } catch (Exception ex2) { Console.WriteLine(ex2.ToString()); } #region Scope2 Console.WriteLine("scope2.{0}\r\n{{", scopeOption2.ToString()); using (MyTransactionScope scope2 = new MyTransactionScope(scopeOption2)) { bool succeed2 = false; try { Console.WriteLine("Read - 0:{0}", db.SelectCreateTimeByCode("0")); Console.WriteLine("Read - 1:{0}", db.SelectCreateTimeByCode("1")); db.DeleteByCode("2"); db.Insert("2", "two"); Console.WriteLine("Insert - 2:{0}", db.SelectCreateTimeByCode("2")); throw new Exception("test"); db.DeleteByCode("22"); db.Insert("22", "two-two"); Console.WriteLine("Insert - 3:{0}", db.SelectCreateTimeByCode("3")); succeed2 = true; } catch (Exception ex2) { Console.WriteLine(ex2.ToString()); } //Suppress不需要提交 if (scopeOption2 != TransactionScopeOption.Suppress && succeed2) { scope2.Complete(); Console.WriteLine("scope2.Complete()\r\n}"); } else { Console.WriteLine("}"); } } #endregion //Suppress不需要提交 if (scopeOption1 != TransactionScopeOption.Suppress && succeed1) { scope1.Complete(); Console.WriteLine("scope1.Complete()\r\n}"); } else { Console.WriteLine("}"); } } #endregion TransactionScopeOption scopeOption3 = TransactionScopeOption.RequiresNew; using (MyTransactionScope scope3 = new MyTransactionScope(scopeOption3)) { Console.WriteLine("scope3.{0}\r\n{{", scopeOption3.ToString()); bool succeed3 = false; try { Console.WriteLine("Read - 0:{0}", db.SelectCreateTimeByCode("0")); Console.WriteLine("Read - 1:{0}", db.SelectCreateTimeByCode("1")); Console.WriteLine("Read - 2:{0}", db.SelectCreateTimeByCode("2")); db.DeleteByCode("3"); db.Insert("3", "three"); Console.WriteLine("Insert - 3:{0}", db.SelectCreateTimeByCode("3")); succeed3 = true; } catch (Exception ex3) { Console.WriteLine(ex3.ToString()); } //Suppress不需要提交 if (scopeOption3 != TransactionScopeOption.Suppress && succeed3) { scope3.Complete(); Console.WriteLine("scope3.Complete()\r\n}"); } else { Console.WriteLine("}"); } } //if (commit) //{ // try // { // db.Insert("1", "first1"); // } // catch (Exception ex1) // { // commit = false; // Console.WriteLine(ex1.ToString()); // } //} if (commit) { scope.Complete(); Console.WriteLine("Complete()"); } } } catch (Exception ex) { Console.WriteLine("Trans Error:" + ex.ToString()); } Console.WriteLine("------------------"); Console.WriteLine("Final - 0:{0}", db.SelectCreateTimeByCode("0")); Console.WriteLine("Final - 1:{0}", db.SelectCreateTimeByCode("1")); Console.WriteLine("Final - 2:{0}", db.SelectCreateTimeByCode("2")); Console.WriteLine("Final -22:{0}", db.SelectCreateTimeByCode("22")); Console.WriteLine("Final - 3:{0}", db.SelectCreateTimeByCode("3")); }
/// <summary> /// 销毁资源 /// </summary> public void Dispose() { /********************************************************************* ** 说明:不管当前实例是哪个,只会按照“事务链”进行处理。即始终都是处理currentScope。 ** rootScope的Option可能是:Required,RequiresNew,Suppress ** currentScope不是rootScope的情况下,Option可能是:RequiresNew,Suppress ** ** 主体逻辑: ** if (currentScope.ScopeOption == Suppress) ** { ** 没有可提交的内容,直接. ** } ** else ** { ** 提交当前层级事务后,根据“事务链”更新currentScope。 ** } ** 根据“事务链”更新currentScope。 ** 如果当前处理的是根级事务,则将事务环境置空。 *********************************************************************/ if (rootScope == null || currentScope == null) { return; } if (this.hostScopeID != Guid.Empty) { return; } if (this.scopeID != currentScope.scopeID) { throw new ApplicationException("事务调用顺序不正确"); } lock (lockObj) { try { if (currentScope.ScopeOption != System.Transactions.TransactionScopeOption.Suppress) { currentScope.DisposeCore(); } } finally { if (rootScope.ScopeID == currentScope.ScopeID) { if (rootScope.scopeStack != null) { rootScope.scopeStack.Clear(); rootScope.scopeStack = null; } rootScope = null; currentScope = null; } else { if (rootScope.scopeStack != null && rootScope.scopeStack.Count > 0) { currentScope = rootScope.scopeStack.Pop(); } else { currentScope = rootScope; } } } } }