先說一下為什麼要說到交易處理,實際上對於資料處理來說,對於資料庫來說,整個程式開發發展到現在,任何程式任何項目都離不開資料處理,資料庫,事務是一個非常重要的概念,不僅是ASP.NET當中甚至其他的程式設計語言編程環境當中,交易處理是一個非常重要的問題,也就是說交易處理本身是超脫於ASP.NET這個範圍的;
1-有人問了什麼是交易處理?
事務是一組組合成邏輯工作單元的資料庫操作(所以看到這大家應該明白,事務是相對於資料庫操作來的,事務本身是因為資料庫的出現而出現的,為了對資料庫操作過程中出現的問題而提出了事務的概念),雖然系統可能出錯,但是事務將控制和維護每個資料庫的一致性和完整性,也就是說交易處理的目的是為了維護資料庫的一致性和完整性,並且事務是個單元,所謂的單元就是如果沒有錯誤的話就修改成功,這樣理解作為事務來說這些基本的操作要麼全部成功,要麼全部失敗,我們知道這是在任何資料庫當中都會遇到的這樣一個問題;
2-交易處理的過程是怎樣的呢?
交易處理流程是和資料庫沒有關係的,也就是說任何的資料庫都是遵照這個流程來做的;1:開始一個事務,進入”事務待命“狀態;2:在“事務待命”狀態,記錄事務中改變的資料庫記錄,注意不能直接改變資料庫當中的值,必須先用一個順序的”交易記錄“記錄在一邊,(把它記下來,要改哪些,把它記在交易記錄當中),同時對要改變的原始記錄進行加鎖,讓其他使用者無法讀寫(無法讀寫就是同一個時刻呢我們只允許一個使用者對某個資料進行讀寫,這樣的目的是為了提高保證資料的一致性),如果記錄已被其他事務加鎖,就報錯;3:在“事務待命”狀態如果使用者給出Commit Transaction 命令,則進入事務拷貝狀態,拷貝所有加鎖的記錄成備份(為什麼備份,為了以後出錯的時候還能返回);4:上面3執行完了,則進入”事務更新狀態“,這是關鍵的更新狀態(不是一上來就更新,首先藥記錄下來要對哪些值進行更新,然後把要更新的值複製一份作為備份,然後在進行更新),用“交易記錄”中的記錄一一更新實際的資料庫記錄;5:上面4執行完則進入“事務結束狀態”,釋放所有的記錄鎖,然後拋棄“交易記錄”和備份的資料庫記錄;6:上面作完後刪除事務,這是一個常見的交易處理的過程,這個是和資料庫沒有關係的;但是最為關鍵的是交易處理必須執行以下過程:一但資料庫由於軟體或者硬體問題發生故障,重啟後,一但有事務沒有正常刪除,這是交易處理最最核心,最最關鍵的部分,如果出錯怎麼辦,我們剛才假設總是沒有出錯,但是作為程式員來說,我們編程的時候是不都要想的全面一些呢,則:7:如果在“事務待命”和“事務結束”狀態,則重新從5中結束事務的動作開始執行;8:如果在“事務更新”狀態,則重新從4開始更新記錄,並向下執行,結果雖然系統崩潰過,但事務仍然能正常提交;
3-交易處理舉例
有人說你用教條解釋了交易處理的流程,不是很明白,對了我本人也是非常討厭教條式的概念和理論,沒有實際生活中來的例子生動形象,好了,那我給大家舉得例子,例子如下:
銀行取款的例子,比如:小王拿著一張卡去銀行取錢了,他這次的目的是取100元,取款機裡面有200元,取錢的流程是:A判斷餘額-B取錢-C扣除(200-100=100),如果取錢的過程中出錯了怎麼辦,本來已經把100元取走了,還沒有扣除,如果在這個時候取款機突然報錯,機器死機了,取走100元結果取款機裡面還有200元,還是顯示200元,如果不作為一個事務來做的話,就會出現這樣的情況,銀行要賠錢了,所以要作為一個事務來處理,如果發現200元取走了100元取錢的動作已經完成了,當系統重新啟動以後,繼續執行扣除,最後把你取走的100元扣掉,雖然我們的系統崩潰了,但是系統重新啟動以後,繼續把沒有做完的事務做完ABC則作為一個邏輯單元來存在;在假如甲乙兩個人同時取錢的話,就要保證同時某一刻只能有一個人取錢(同時只有一個人做ABC三個動作,為了保證資料的一致性),如果說甲取了100元,但是還沒來得及扣除情況下,銀行裡面顯示還是200元,乙要再取的話還能取,實際上這種情況不能再取了,所以我們要保證資料的一致性,保證銀行不賠錢,所以我們經常會遇到對資料庫處理的時候是不要加鎖,講到這裡就明白了,加鎖的目的就是讓同一時刻對某一個資料只有一個人進行操作,而且作為ABC這三個動作來說呢,把它作為一個事務來處理,要麼全部成功,要麼全部失敗,既然錢取走了,就一定要扣掉,系統雖然崩潰了,重新啟動後還要把這個事務作完;
通過這個銀行取錢的例子大家明白了吧;
4-交易處理的有關事項
交易處理的關鍵在於為了防止這樣的情況,萬一系統崩潰了,資料庫再次啟動後,仍然保持資料的一致性,邏輯性,也就是交易處理在這個時候發生的,如果說正正常常的,交易處理相對來說它就沒有起到作用,就是預防萬一出錯的情況下,應用中包含的事務應當盡量讓他瞬間完成的,也就是說一個事務很快的完成的,否則你說他取錢和扣除的過程,我們上個例子ABC三個動作應該馬上立馬完成的,如果說他取錢和扣除用上10分鐘的話,你想想其他的人沒法取錢了,避免在比較忙的時候造成使用者進程的互鎖,在這種情況下也是為了提高效率,所以作為一個事務來說應該是很快完成的,事務是要加鎖的,也就是某一個時刻向下呢一個事務必須執行,其他不能同時訪問了,特別是進行更新,我們知道電腦它崩潰的外因是不可預料的,特別是對於銀行,使用者的保密的資料作好資料的一致性是非常非常重要的,千萬不能出任何的差錯,所以交易處理是業務系統安全穩定的最後一道防線;
5-那交易處理有哪些方法呢?
1:直接寫入SQL
直接寫SQL語句,SQL語句本身是可以有事務的,有交易處理的;在預存程序中使用Begin Tran,Commit Tran RollBack Tran。優點:獨立於應用程式,擁有運行一個事務的最佳效能(在預存程序寫交易處理是效能最好的)。限制:交易處理的上下文僅存在於資料庫調用中(交易處理只能在SQL語句中體現,如果在SQL語句之外是無法訪問的),資料庫代碼與資料庫系統相關的(因為是SQL語句當中進行的交易處理,不同的資料庫寫的方法不一樣);
2:通過ADO.NET實現
我們說在.NET當中呢,通過ADO.NET可以實現交易處理;在ADO.NET中使用Connection和Transacion對象來控制事務,若要執行事務請執行以下操作:調用Connrction對象的BeginTransaction方法標記一個事務的開始(BeginTransaction返回一個Transaction對象),將Transaction對象分配給要執行的Command的Transaction屬性(將這個Tranaction對象賦值給Command對象的Transaction屬性),調用Transaction對象的Commit方法來完成事務,或調用Rollback來取消事務;優點:簡單性,和資料庫事務差不多得快,獨立於資料庫。缺點:不能跨越多個資料庫,事務執行在資料庫連接層上,所以需要在事務中維護一個資料庫連接。
3:COM+事務(分散式交易)
在某些特定的情況下,我們要用的;一般的資料庫事務控制要求事務裡所做的操作必須在同一個資料庫內(必須對同一個資料庫進行操作),這就存在一個問題,在分布式應用程式中,我們往往要同時操作多個資料庫,SQLServer,Oracle,MySQL,你可能要操作兩個資料庫甚至多個資料庫,你也希望這些操作要麼同時成功,要麼同時失敗,也就是他們要做一個事務來處理,這種情況下就要用COM+的分散式交易處理了;
上面提到的交易處理的核心在於為了防止系統崩潰了,資料庫再次啟動後,仍然保持資料的一致性,邏輯性;
不過其實事務還有一點在我們實際的應用中非常重要的一點,比如:有個進銷存系統,當採購成功的時候,資料表Order
(訂單表)裡插入一條記錄,同時OrderInfo(訂單明細表)裡插入多條這個訂單的明細記錄,如果成功都成功,如果失敗都失敗,不可能,有訂單的記錄,沒有訂單明細的記錄吧,也不可能有訂單明細的記錄,沒有訂單的記錄吧;
不過個人認為在目前我們所做的項目中用到COM+事務的情況不多見,因為我們大部分都是操作同一個資料庫;
鑒於有網友提出文章只是講到純理論,沒有執行個體,所以特意補上執行個體以供參考,先說一下我們做事情先明白為什麼要這麼做,這麼做的原因是什麼,不這麼做會導致什麼後果,如果會導致後果那麼這個後果發生的機率有多大。而現在很多書本上都是一步步指導你怎樣做,怎樣開發,卻始終未曾提及為什麼要這麼做;
好了,我就附上在ADO.NET中實現事務的代碼如下:
strConn是連接字串,這裡就不寫明了;
1 /// <summary> 2 /// 插入採購單利用事務 3 /// </summary> 4 /// <param name="order">採購單頭</param> 5 /// <param name="ls">採購單資訊</param> 6 /// <returns>返回插入的表頭id</returns> 7 public int InsertOrder(OrderData order, List<OrderInfoData> orderinfolist) 8 { 9 SqlConnection conn = new SqlConnection(strConn);10 conn.Open();11 SqlCommand cmd = new SqlCommand("insert into [order](Order_No, PurveyInfo_ID, User_ID, Order_Time, Down, Blank, YiTuiHui, ZaiTu, YiShouHuo) values(@order_no, @purveyinfo_id, @user_id, @order_time, 0, 0, 0, 0, 0)", conn);12 SqlTransaction trans;13 trans = conn.BeginTransaction();14 cmd.Transaction = trans;15 List<int> rlist = new List<int>();16 try17 {18 cmd.Parameters.AddWithValue("@order_no", order.Order_No);19 cmd.Parameters.AddWithValue("@purveyinfo_id", order.PurveyInfo_ID);20 cmd.Parameters.AddWithValue("@user_id", order.User_ID);21 cmd.Parameters.AddWithValue("@order_time", order.Order_Time);22 cmd.ExecuteNonQuery();23 cmd.CommandText = "select @@IDENTITY";24 int i = Convert.ToInt32(cmd.ExecuteScalar());25 foreach (OrderInfoData orderinfo in orderinfolist)26 {27 cmd.CommandText = "insert into orderInfo values(@order_id,@merchandiseinfo_id, @price, @quantity, 0)";28 cmd.Parameters.Clear();29 cmd.Parameters.AddWithValue("@order_id", i);30 cmd.Parameters.AddWithValue("@merchandiseinfo_id", orderinfo.MerchandiseInfo_ID);31 cmd.Parameters.AddWithValue("@price", orderinfo.Price);32 cmd.Parameters.AddWithValue("@quantity", orderinfo.Quantity);33 cmd.ExecuteNonQuery();34 }35 trans.Commit();36 return i;37 }38 catch (SqlException ex)39 {40 trans.Rollback();41 throw ex;42 }43 finally44 {45 conn.Close();46 }47 }
以上代碼的意思是當採購成功的時候,資料表Order(訂單表)裡插入一條記錄,同時OrderInfo(訂單明細表)裡插入多條這個訂單的明細記錄,如果成功都成功,如果失敗都失敗;不可能,有訂單的記錄,沒有訂單明細的記錄,也不可能有訂單明細的記錄,沒有訂單的記錄;
本文來自CSDN部落格,轉載請標明出處:
http://blog.csdn.net/menglin2010/archive/2011/01/19/6151360.aspx