本章概要:數據庫
1:事務概述編程
2:隱式事務分佈式
3:顯示事務函數
1:事務概述post
當您從網上書店購買書籍時,會用錢(以信貸方式)來交換書籍。若是您的信用良好,則一系列相關操做可確保您和書店能夠相應地得到書籍和錢。但若是在交換期間該系列操做中的單個操做發生故障,則整個交換就會失敗。結果,您就得不到書籍,而書店也得不到錢。負責使該交換取得平衡且可預測的技術稱爲事務處理。性能
事務操做可限定於單個數據資源,如數據庫或消息隊列。在這種狀況下,本地事務由 System.Transactions 所提供的可提高性能的事務管理器管理。當這些事務由數據資源控制時,它們具備高效性並易於管理。 this
事務也可跨多個數據資源。使用分佈式事務能夠將在不一樣系統上執行的多種不一樣的操做合併到一個經過或失敗的操做中。在這種狀況下,事務由位於每一個系統中的 Microsoft 分佈式事務協調器 (MSDTC) 進行協調。spa
事務也能夠有多個參與者。線程
可以使用 ADO.NET、System.EnterpriseServices 或 System.Transactions 命名空間所提供的新事務性編程模型來建立事務。調試
System.Transactions 命名空間中的類所提供的基礎結構經過支持在 SQL Server、ADO.NET、消息隊列 (MSMQ) 和 Microsoft 分佈式事務協調器 (MSDTC) 中啓動的事務,使事務編程變得簡單和高效。
System.Transactions 命名空間提供基於 Transaction 類的顯式編程模型和使用 TransactionScope 類的隱式編程模型,在後一種模型中,事務由該基礎結構自動管理。此外,System.Transactions 命名空間還提供了用於實現資源管理器的類型。資源管理器管理事務中使用的持久或可變數據,並與事務管理器協調工做,共同爲應用程序提供了原子性和隔離性的保證。由 System.Transactions 基礎結構提供的事務管理器支持的事務可涉及到多個可變資源或單個持久資源。
2:隱式事務
可採用 Transaction 類來利用顯式編程模型,也可採用 TransactionScope 類來利用隱式編程模型(其中的事務將由基礎結構自動管理)。建議您使用隱式事務模型進行開發。
建立新的 TransactionScope 對象後即會啓動事務範圍。建議您使用 using 語句建立範圍,如該代碼示例中所示。
void RootMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ SomeMethod(); scope.Complete(); } } void SomeMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ scope.Complete(); } }
最頂層事務範圍稱爲根範圍。
TransactionScope 的有些重載構造函數接受 TimeSpan 類型的值,該值用於控制事務的超時。超時設置爲零時表示超時無限長。無限長的超時主要對調試有用,調試過程當中可能要經由逐句經過代碼來隔離業務邏輯中的問題,而且在嘗試肯定問題期間不但願所調試的事務超時。在全部其餘狀況下使用無限長的超時時必定要格外當心,由於它會覆蓋防止事務死鎖的保護。
3:顯示事務
CommittableTransaction 類爲應用程序使用事務提供了一種顯式方法,而不是隱式地使用 TransactionScope 類。對於要跨多個函數調用或多個線程調用使用同一事務的應用程序,十分有用。TransactionScope 類不一樣,應用程序編寫器須要明確調用 Commit 和 Rollback 方法以提交或停止事務。
//Create a committable transaction tx = new CommittableTransaction(); SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind"); SqlCommand myCommand = new SqlCommand(); //Open the SQL connection myConnection.Open(); //Give the transaction to SQL to enlist with myConnection.EnlistTransaction(tx); myCommand.Connection = myConnection; // Restore database to near it's original condition so sample will work correctly. myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"; myCommand.ExecuteNonQuery(); // Insert the first record. myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"; myCommand.ExecuteNonQuery(); // Insert the second record. myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"; myCommand.ExecuteNonQuery(); // Commit or rollback the transaction while (true) { Console.Write("Commit or Rollback? [C|R] "); ConsoleKeyInfo c = Console.ReadKey(); Console.WriteLine(); if ((c.KeyChar == 'C') || (c.KeyChar == 'c')) { tx.Commit(); break; } else if ((c.KeyChar == 'R') || (c.KeyChar == 'r')) { tx.Rollback(); break; } } myConnection.Close(); tx = null;