一、事務:它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。html
二、事務特性(ACID):接觸事務,都是從事務的ACID開始,原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。sql
三、事務涉及的對象 :數據庫
資源:應用程序存儲和獲取數據的地方,能夠是數據庫,文件,也能夠是內存。若是是應用程序的事務塊代碼中涉及到的數據庫,文件,內存,那這些資源就稱爲事務型資源。c#
資源管理器:在事務模型中,應用不是直接訪問資源,而是經過中間介訪問資源,這個中間介就叫資源管理器。跨域
資源分爲可持久化資源(對應了持久化資源管理),易失資源(對應了易失資源管理器)。網絡
事務管理器:實現事務的開始、提交、回滾。架構
四、事務提高:併發
輕量級事務管理器:做用於開啓事務的應用程序域,只能包含一個持久化資源,若是再添加一個持久化資源,將被輕量級事務管理器忽略。app
可是能夠登記多個易失資源。目前輕量級事務管理器只支持SQL 2005以及SQL2005以上的版本持久化資源。分佈式
內核事務管理器:在 Vista、Windows Server 200八、WIN7操做系統中,引入了內核事務管理器。
內核事務管理器主要是把文件管理(NTFS文件系統)和註冊表管理歸入事務範疇。咱們將那些支持事務的文件系統和註冊表叫做事務型文件系統(TxF)
和事務型註冊表(TxR)。 之因此稱爲內核事務管理器,是因它運行在內核模式上, 而不是在用戶模式上。一樣內核事務管理器只支持一個持久化資源。
分佈式事務協調器:每一臺電腦上只有一個分佈式事務協調器,它管理了當前計算機的全部事務資源。它能夠跨程序域,跨進程,跨機器,跨網絡來執行事務。
當事務跨機器時,每臺機器的分佈式事務協調器按照相應的協議工做,實現對整個事務的管理,它對應的事務管理協議有Ole-Tx和
WS-Atomic Transaction(WS-AT)這些。 分佈式事務協調器可以管理一個分佈式事務涉及的全部事務型資源,無論具體的事務型資源分佈在何處。
事務提高:事務是一個動態執行的操做序列,在整個過程當中,不可能預知資源的登記狀況。因此輕量級事務管理器做爲默認的事務管理器,隨着事務的逐步執行,
若是涉及到內核事務資源,那麼將提高爲內核事務管理器。若是出現對多個事務資源的訪問,或者當前事務涉及跨域(調用另一個服務),就會提高
爲分佈式事務協調器。Windows採用事務提高機制進行事務管理器的選擇。
一、本地事務: 輕量級事務管理器,內核事務管理器都只支持本地事務。本地事務相對簡單,這兒不做重點簡述。
二、分佈式事務:理解分佈式事務是怎樣實現的,事務提交樹是關鍵。
事務提交樹:事務提交樹的根是事務初始化服務所在的機器的DTC,它在整個事務提交過程當中充當着總協調者,又被稱爲全局提交協調器。
資源管理器充當着事務提交樹的葉子節點,它們的父結點爲本機的DTC,分佈於不一樣機器的DTC按照事務的傳播路徑造成了上下級關係。
在一個分佈式事務中,事務的初始化和提交是屬於一個對象,只有最初開始的事務才能被提交,咱們將這種能被初始化和提交的事務稱做可提交事務。
隨着參與者逐個登記到事務中,它們本地的事務實際上依賴着這個最初開始的事務,因此咱們稱這種事務叫依賴事務。
在MSDN上對文件事務有詳細的闡述 使用文件系統事務加強您的應用程序 咱們若是是仔細閱讀這篇文章不難發現他提供了一個.exe類型文件的下載。先把這個TxF2007_07.exe文件下載到本地硬盤,執行它,能夠獲得一個關於 c#的 KtmIntegration.csproj 的項目,咱們用visual studio來打開這個項目,而且從新重成這個項目,能夠獲得一個KtmIntegration.dll文件。
在你要實現的文件事務的項目中引入這個.dll文件,那你就能夠很順利的實現文件事務的操做了。
具體代碼:
using System; using System.IO; using System.Transactions; using Microsoft.KtmIntegration; namespace Exercise.WebLocalTransaction { public partial class Test02 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { using (TransactionScope transactionScope = new TransactionScope()) { try { FileStream stream = TransactedFile.Open( @"D:/Sam Xiao.txt" , FileMode.OpenOrCreate , FileAccess.ReadWrite , FileShare.ReadWrite); StreamWriter writer = new StreamWriter(stream); writer.WriteLine(String.Concat("執行一個事務代碼:",DateTime.Now.ToString(),Environment.NewLine)); writer.Close(); //int x = 0; //int y = 10; //int z = y / x; transactionScope.Complete(); } catch { } } } } }
不要忘記了引入using Microsoft.KtmIntegration;名稱空間。在段代碼沒有異常的狀況下,咱們能夠看到D盤裏順利建立了一個關於Sam Xiao.txt的文件。
咱們故意在這段代碼中拋出一個被0整除的異常,那麼整個操做就會回滾。
在.net平臺上,主要是經過WCF的手段來實現程序的分佈式開發。
在WCF事務體系:主要解決了事務在服務中的流轉,以及解決服務內部直接或間接訪問事務型資源的協做。
用WCF來演示事務的時候,要選擇好WCF的綁定類型,有一部份綁定是不支持WCF的事務傳播的。咱們選擇wsHttpBinding 來作WCF的事務演示。
一、首先定義好WCF的服務契約
[ServiceContract(Name = "IBankingService")] public interface IBankingService { [TransactionFlow(TransactionFlowOption.Mandatory)] [OperationContract(Name = "Transfer")] void Transfer(string fromAccountId, string toAccountId, double amount); [TransactionFlow(TransactionFlowOption.Mandatory)] [OperationContract(Name = "Pay")] bool Pay(String accountID, double amount); [TransactionFlow(TransactionFlowOption.Mandatory)] [OperationContract(Name = "Receipt")] bool Receipt(String accountID, double amount); }
二、實現WCF的服務
[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable)]
public class BankingService : IBankingService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void Transfer(string fromAccountId, string toAccountId, double amount)
{
throw new NotImplementedException();
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool Pay(string accountID, double amount)
{
throw new NotImplementedException();
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool Receipt(string accountID, double amount)
{
throw new NotImplementedException();
}
}
3,WCF宿主配置
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="sBehaviorConfig">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wshttpConfig" transactionFlow="true" >
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Exercise.Service.BankingService" behaviorConfiguration="sBehaviorConfig">
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wshttpConfig" contract="Exercise.Contract.IBankingService"></endpoint>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
4,WCF客戶端配置
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBankingService" transactionFlow="true">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9100/BankingService.svc/mex"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IBankingService"
contract="Exercise.Contract.IBankingService" name="WSHttpBinding_IBankingService" />
</client>
</system.serviceModel>
5,調用服務
IBankingService bankService = WcfProxy.CreateProxy<IBankingService>("WSHttpBinding_IBankingService");
protected void Page_Load(object sender, EventArgs e)
{
using (TransactionScope transactionScope = new TransactionScope())
{
bankService.Pay("111", 50);
bankService.Receipt("222", 50);
transactionScope.Complete();
}
}
以上內容來自:http://www.cnblogs.com/xcj26/archive/2013/12/23/3469373.html 感謝做者的貢獻!
當一個表數據更新後,怎麼保證另外一個表的數據也必需要更新成功?
例如:
從支付寶轉帳1萬塊錢到餘額寶:支付寶扣除1萬以後,若是正好系統掛掉,這時餘額寶帳戶並無增長1萬,數據就會出現不一致情況了 。同理,在電商系統中,當有用戶下單後,除了在訂單表插入一條記錄外,對應商品表的這個商品數量必須減1吧,怎麼保證? 在搜索廣告系統中,當用戶點擊某廣告後,除了在點擊事件表中增長一條記錄外,還得去商家帳戶表中找到這個商家並扣除廣告費吧,怎麼保證?
支付寶帳戶表:A(id,userId,amount)
餘額寶帳戶表:B(id,userId,amount)
用戶的userId=1;
若是系統規模較小,數據表都在一個數據庫實例上,上述本地事務方式能夠很好地運行;可是若是系統規模較大,好比支付寶帳戶表和餘額寶帳戶表顯然不會在同一個數據庫實例上,他們每每分佈在不一樣的物理節點上,這時本地事務已經失去用武之地。
兩階段提交協議(Two-phase Commit,2PC)常常被用來實現分佈式事務。通常分爲協調器C和若干事務執行者Si兩種角色,這裏的事務執行者就是具體的數據庫,協調器能夠和事務執行器在一臺機器上。
注:TC或Si把發送或接收到的消息先寫到日誌裏,主要是爲了故障後恢復用。如某一個Si從故障中恢復後,先檢查本機的日誌,若是已收到<commit >,則提交,若是<abort >則回滾。若是是<yes>,則再向TC詢問一下,肯定下一步。若是什麼都沒有,則極可能在<prepare>階段Si就崩潰了,所以須要回滾。
該解決方法存在問題: 性能實在是太差,根本不適合高併發的系統。
正是因爲分佈式事務存在很嚴重的性能問題,大部分高併發服務都在避免使用,每每經過其餘途徑來解決數據一致性問題。
在飯館點了菜並付了錢後,他們並不會直接把你點的菜給你,而是給你一張小票,而後讓你拿着小票到出貨區排隊去取。爲何他們要將付錢和取貨兩個動做分開呢? 緣由不少,其中一個很重要的緣由是爲了使他們接待能力加強(併發量更高)。
仍是回到咱們的問題,只要這張小票在,你最終是能拿到點的菜的。同理轉帳服務也是如此,當支付寶帳戶扣除1萬後,咱們只要生成一個憑證(消息)便可,這個憑證(消息)上寫着「讓餘額寶帳戶增長 1萬」,只要這個憑證(消息)能可靠保存,咱們最終是能夠拿着這個憑證(消息)讓餘額寶帳戶增長1萬的,即咱們能依靠這個憑證(消息)完成最終一致性。
有兩種方法:業務與消息耦合的方式、業務與消息解耦方式。
支付寶在完成扣款的同時,同時記錄消息數據,這個消息數據與業務數據保存在同一數據庫實例裏(消息記錄表表名爲message)。
Begin transaction update A set amount=amount-10000 where userId=1; insert into message(userId, amount,status) values(1, 10000, 1); End transaction commit;
上述事務能保證只要支付寶帳戶裏被扣了錢,消息必定能保存下來。
當上述事務提交成功後,咱們經過實時消息服務將此消息通知餘額寶,餘額寶處理成功後發送回覆成功消息,支付寶收到回覆後刪除該條消息數據。
上述保存消息的方式使得消息數據和業務數據緊耦合在一塊兒,從架構上看不夠優雅,並且容易誘發其餘問題。爲了解耦,能夠採用如下方式:
爲何須要這一步驟,舉個例子:假設在第2步支付寶扣款事務被成功提交後,系統掛了,此時消息狀態並未被更新爲「確認發送」,從而致使消息不能被髮送。
該方法優勢:消息數據獨立存儲,下降業務系統與消息系統間的耦合;
該方法缺點:一次消息發送須要兩次請求;業務處理服務須要實現消息狀態回查接口。
還有一個很嚴重的問題就是消息重複投遞,以咱們支付寶轉帳到餘額寶爲例,若是相同的消息被重複投遞兩次,那麼咱們餘額寶帳戶將會增長2萬而不是1萬了。
爲何相同的消息會被重複投遞? 好比餘額寶處理完消息msg後,發送了處理成功的消息給支付寶,正常狀況下支付寶應該要刪除消息msg,但若是支付寶這時候悲劇的掛了,重啓後一看消息msg還在,就會繼續發送消息msg。
解決方法很簡單,在餘額寶這邊增長消息應用狀態表(message_apply),通俗來講就是個帳本,用於記錄消息的消費狀況,每次來一個消息,在真正執行以前,先去消息應用狀態表中查詢一遍,若是找到說明是重複消息,丟棄便可,若是沒找到才執行,同時插入到消息應用狀態表(同一事務)。
for each msg in queue Begin transaction select count(*) as cnt from message_apply where msg_id=msg.msg_id; if cnt==0 then update B set amount=amount+10000 where userId=1; insert into message_apply(msg_id) values(msg.msg_id); End transaction commit;