交易處理過程
事務的處理過程大體分為幾個步驟:1.事務的組裝;2.相應資料集合的加鎖;3.通知數據集合備份;4.順序執行每一個原子操作;5.為每一個原子操作的成功位做標示;6儲存結果返回到結果池中
事務的組裝在用戶端需要自行完成,因為每個用戶端提交的任務不相同,伺服器都做統一的處理。事務組裝的代碼如下:
Boolean success = false; #region 組裝成一個事務,並返回結果 TransactionEntity transactionEntity = new TransactionEntity();//準備提交的參數 Hashtable ResultHashTable = new Hashtable();//準備返回的參數 transactionEntity.TransactionID.Add("14");//編號21:預訂酒店 transactionEntity.TransactionParam.Add(new object[] { locationString, hotelRemoteService });//參數 transactionEntity.TransactionID.Add("19");//編號19:添加預訂資訊 transactionEntity.TransactionParam.Add(new object[] { CustNameString, 2, reservationRemoteService });//參數 queueTransactionService.intTransactionID += 1;//事務編號 int intTransactionID = queueTransactionService.intTransactionID; queueTransactionService.globalControlService = globalControlService;//分配新的事務編號 queueTransactionService.AddEntity(intTransactionID.ToString(), transactionEntity);//把需要處理的事務裝在hashtable隊列裡面,等待程式自動處理 while (true)//迴圈檢查結果隊列,尋找自己的事務結果 { if (queueTransactionService.TransactionResult.ContainsKey(intTransactionID.ToString()))//在結果清單中尋找到了自己需要的資料,跳出無限等待 break; } ResultHashTable = (Hashtable)queueTransactionService.TransactionResult[intTransactionID.ToString()];//接受從伺服器來的結果 success = (Boolean)ResultHashTable["14"]; if (success == true) { MessageBox.Show("酒店預定成功,地點:" + locationString); } else { MessageBox.Show("酒店預定失敗!"); } #endregion
事務的組裝首先需要執行個體化事務實體類(TransactionEntiy)和結果接受類(Hashtable)。下一步需要填充TransactionEntiy,整個TransactionEntiy只有三個參數,兩個需在這裡填充,只有每個操作是否成功需要在用戶端填充並且處理檢測。添加好事務的序號後,用戶端需要做的就是把事務丟進事務池(Transaction Pool)中等待程式區運行。這時候用戶端需要族的就是去結果池(Result Pool)中等待並且尋找自己的結果。樣本圖如下:
事務池和結果池
在執行這個事務之前,需要對其所涉及的所有資料集合進行加鎖,即修改其hasControl標誌段的值。在對其加鎖的同時,也通知該資料集合進行備份,以便事務撤銷的時候不能恢複到原來的狀態。程式碼片段如下:
/// <summary> /// 執行一個事務,把結果儲存在Hashtable中,此過程會自動加鎖,對資料集合進行備份 /// </summary> /// <param name="TansactionHashTable">需要執行的事務,包括每一個操作的編號和所需要的參數</param> /// <returns>返回結果,按照每一個操作得到的結果儲存在Hashtable裡面</returns> public Hashtable ProcessTransaction() { for (int i = 0; i < TransactionEntity.TransactionID.Count; i++) { //對所需要的資料集合進行加鎖 LockByID(TransactionEntity.TransactionID[i]); //開始這個事務,通知相關資料集合伺服器做相應的處理 BeginByID(TransactionEntity.TransactionID[i], xid); }
迴圈遍曆事務中的每一個操作,找到其編號,根據編號執行相應的操作,並把結果放在相應的集合中。
Hashtable TransactionResult = new Hashtable(); for (int i = 0; i < TransactionEntity.TransactionID.Count; i++) { try { //把方法編號和方法返回結果儲存到hashtable裡面,用於返回給用戶端 object ObjResultTmp = GetDataByID(TransactionEntity.TransactionID[i], TransactionEntity.TransactionParam[i]); if (ObjResultTmp == null)//如果該傳回值為空白,則說明沒有取到資料或者操作失敗,則執行失敗 TransactionEntity.Success.Add(false); else TransactionEntity.Success.Add(true); TransactionResult.Add(TransactionEntity.TransactionID[i], ObjResultTmp); } catch (Exception e) { TransactionEntity.Success.Add(false); } }
一次事務的執行並不一定能成功,如果有一個操作失敗了,那麼就意味著整個事務都必須要復原到初始狀態,所以在每一個操作執行完畢後,都會為其標誌位進行賦值。標誌為失敗的情況主要分為幾個情況:1.返回結果為空白,說明執行失敗;2.執行存在錯誤跑到Catch地區了。這兩種情況都視為操作失敗。
int flag = 1;//標記為,1為全部成功,0為有失敗 //通過迴圈來查看是否有那個執行沒有成功 for (int i = 0; i < TransactionEntity.Success.Count; i++) { if (TransactionEntity.Success[i].Equals(false))//如果有失敗的操作,那麼將整個交易回復,具體操作為還原相應的資料集合 { flag = 0;//有失敗 break; } }
無論此事務成功或者失敗,都需要給資料集合一個交代。事務執行的最後,需要做的就是判斷此事務是需要提交還是復原。
//判斷是否進行復原 if (flag == 0)//到此,失敗,復原 for (int i = 0; i < TransactionEntity.TransactionID.Count; i++) { RollBackByID(TransactionEntity.TransactionID[i], xid); } else for (int i = 0; i < TransactionEntity.TransactionID.Count; i++) { //到此,說明整個事務執行成功 CommiteByID(TransactionEntity.TransactionID[i], xid); } //執行結束,解鎖 for (int i = 0; i < TransactionEntity.TransactionID.Count; i++) { UnlockByID(TransactionEntity.TransactionID[i]); }
最後無論復原還是執行,都需要釋放掉所佔用的資源,保證其他事務能夠正常運行。