本文將針對以下幾個問題給大家解答:
1)什麼是事務?事務有哪些特性?
2)不同隔離級別的事務,有什麼區別?
3)瞭解一下資料庫鎖:共享鎖,更新鎖,排它鎖
4)資料庫事務和鎖之間有什麼關係?
5)擴充:什麼是分散式事務?有哪些解決方案?
事務
通常是指包含了多個資料庫執行操作(select,update,delete,insert)的一個程式執行單元。
事務的四大特性ACID:
1.原子性(Atomicity):事務中所有資料庫操作要麼全部執行成功,要麼全部執行失敗。
2.一致性(Consistency):事務執行前後資料庫狀態保持一致。比如付款操作:A賬戶減少100元,相應的B賬戶增加100元。
3.隔離性(Isolation):事務與事務之間相互隔離,互不影響,保證了事務之間資料處理的獨立性。
4.永續性(Durability):事務一旦提交成功,那麼對資料庫資料的影響必將持久化到資料庫中,不會因為外在環境,比如斷電,伺服器當機等因素而影響對資料庫資料的變化。事務提交成功之後,會首先記錄到資料庫日誌檔案中,即使斷電重啟後,也會繼續讀取日誌完成事務操作。
事務分類:根據事務中涉及的資料庫操作例項數量區分
本地事務:事務僅針對同一個資料例項進行操作, 例如:.Net中具體實現如SQLtransaction
分散式事務:事務中針對多個資料庫例項進行操作。例如:.Net中的DTC分散式事務,具體實現TransactionScope
事務的隔離性,將事務分為不同隔離級別
1.未提交讀(Read UnCommitted) :允許該事務讀取其他事務未提交的資料。
存在問題:髒讀
2.已提交讀 (Read Committed):允許該事務讀取其他事務已提交的資料。
解決了髒讀的問題
存在問題:不可重複讀,事務中前後讀取資料不一致。
3.可重複讀 (Repeatable Read):同一個查詢,保證該事務讀取前後資料一致。
解決了不可重複度的問題
存在問題:幻讀 ,可能讀取到其他事務新增的資料。
4.序列讀(Serializable):要求事務序列化執行,事務只能一個接著一個地執行,不能併發執行。
解決了幻讀的問題
SQLServer資料庫事務語法:
SET TRANSATION ISOLATION LEVEL READ UNCOMMITTED--設定事務隔離級別 BEGIN TRANSACTION ... ...--事務執行內容 ... COMMIT/ROLLBACK--提交或者回滾
資料庫鎖
1.共享鎖(S)
1)保護讀取的資料,讀取的過程中,其他併發事務不能修改,刪除資料,可以併發讀取。
2)當事務隔離級別低於“可重複讀”時,一旦資料讀取結束,立即釋放共享鎖,和事務是否結束無關。
2.排它鎖(X)
1)保護修改的資料,獲取當前被修改資源的鎖,該資源同一時刻只能被一個排它鎖佔有,不允許其他併發事務操作該資源(讀取和修改)。
2)排它鎖和共享鎖不能相容。當修改資源時,會自動由共享鎖升級為排它鎖,因此必須等待資源釋放共享鎖,才能獲得排它鎖。
3)如果排它鎖存在於事務中,需等事務結束才能釋放鎖。
3.更新鎖(U)
1)更新鎖時介於共享鎖和排它鎖中間的混合。更新鎖通過uplock手動新增,分兩個階段:1.在修改操作之前,通過更新鎖獲取資源物件 ,其他事務執行緒則只能讀取不能操作 2.然後執行修改操作,將更新鎖升級為排它鎖。在修改操作前實現對資源鎖定,避免了死鎖。
2)更新鎖和共享鎖可以共存,因此使用更新鎖比使用排它鎖解決死鎖問題,效能更優。
3)持有更新鎖的資源,允許被其他併發事務select。
4)如果更新存在於事務中,需等事務結束才能釋放更新鎖。
事務與鎖之間的關係
首先我們說事務和資料庫鎖之間沒有必然的聯絡,但是事務的執行時間會影響鎖持有的時間,間接影響了資料執行效率。
1.通常在執行select查詢的時候會持有共享鎖,查詢一旦執行結束,則立即釋放共享鎖。如果在事務中執行查詢,且隔離級別低於可重複讀,即使事務沒有執行結束,也不會影響共享鎖的釋放。
2.更新鎖和排它鎖,通常在語句執行結束後會立即釋放鎖資源。如果在事務中執行相關鎖操作,需等待事務執行結束,才能釋放鎖。
3.update語句天然就會持有排它鎖,即使不在事務中執行update操作也會持有鎖。
4.事務隔離級別未提交讀(Read UnCommitted)等同於select查詢新增with(nolock),允許讀取“髒資料”
語法:
select * from sys.objects with(nolock) where name='sysrscols';
5.事務隔離級別中的未提交讀、已提交讀和可重複讀都是行級別鎖,對條件範圍內的行資料持有鎖。
6.事務如何通過隔離級別處理併發,以“可重複讀”隔離級別為例:
1)事務A,預設隔離級別“已提交讀”,查詢操作5秒後執行更新操作
BEGIN TRAN SELECT * FROM [ORDER] WHERE ID='10' WAITFOR DELAY '00:00:05' UPDATE [ORDER] SET PRICE=30 WHERE ID='10' COMMIT TRAN
2)事務B,隔離級別“可重複讀”,前後兩次查詢間隔10秒
SET TRAN ISOLATION LEVEL SERIALIZABLE BEGIN TRAN SELECT * FROM [ORDER] WHERE ID='10' WAITFOR DELAY '00:00:10' SELECT * FROM [ORDER] WHERE ID='10' COMMIT TRAN
3)啟動事務A後,立即啟動事務B,事務具體執行順序如下:
a)事務A執行查詢,並持有ID=10資料的共享鎖,查詢結束後釋放鎖,並等待5秒
b)事務B執行查詢,並持有ID=10資料的共享鎖,由於隔離級別是可重複讀,因此查詢結束後也一直持有共享鎖資源,並等待10秒。
c)事務A5秒等待結束後,執行update申請持有ID=10資料的排它鎖,此時事務B已經持有了共享鎖,由於共享鎖和排它鎖互斥,所以事務A申請排它鎖失敗,繼續等待事務B釋放鎖資源。這裡其實也正是“可重複讀”隔離級別解決“不可能重複”問題的關鍵。
d)事務B10秒等待結束後,繼續執行下一個select查詢,並申請持有ID=10資料的共享鎖,由於共享鎖可以共存,事務B申請成功並完成查詢,前後查詢資料保持一致。
e)事務A在事務B執行結束後,立即獲取到ID=10資料的排它鎖,並執行成功,事務A結束釋放鎖資源。
擴充:
鎖分類:
悲觀鎖:使用資料庫鎖機制,犧牲併發效能,保持事務一致性。
樂觀鎖:不使用資料庫鎖機制,通常可通過操作前後校驗資料的方式,比如欄位中增加一個版本號version,如果更新前後版本號一致,則執行成功 否則返回錯誤提示,也能保證事務的一致性。
分散式事務
本地事務都是操作的本地單資料庫,分散式事務中不同的操作可能涉及多個不同伺服器上的資料庫例項,因此本地事務不再滿足。
解決方案:
1.兩階段提交(2PC)
準備階段:事務協調者詢問事務中的每個資料庫參與者是否都執行事務成功,如果成功則進入下階段。
提交階段:事務協調者通知事務中每個參與者提交執行操作。
目前.Net中分散式事務支援TransactionScope 需啟動MSDTC服務,即事務協調者。
特點:需要事務中涉及的每個參與者反饋成功才能最終提交,滿足事務一致性,但是阻塞較長。
2.事務補償機制(TCC)
該機制將事務中每個操作都註冊對應的確認和補償操作:分為三個階段
1.try階段:主要是對業務系統做檢測和預留
2.confirm階段:做確認提交,一旦try階段成功,則預設confirm成功
3.cancel取消階段:如果步驟執行失敗,執行回滾。
3.本地事務+MQ訊息
將分散式事務分為多個本地事務,不同伺服器上的本地事務通過MQ訊息傳送。MQ分發的內容需要通過中間訊息表進行記錄並分發。滿足事務最終一致性原則。
如:一個分散式事務中包含A,B兩個不同資料庫伺服器上的操作,A操作執行本地事務+訊息表記錄B操作,MQ傳送訊息表資訊,如果B伺服器接收到資訊,返回訊息接收成功。那麼A本地事務就會執行結束並提交。至於B伺服器是否執行成功,A伺服器不再關心。B伺服器接收到訊息之後,會在B本地事務執行,如果執行失敗,則會一直重試,直到執行成功,以保持事務最終一致性。
其中如果A傳送佇列失敗,也會重試傳送。