1. 程式人生 > >數據庫事務4種隔離級別和7種傳播行為

數據庫事務4種隔離級別和7種傳播行為

事物 程序 單位 oracle 異常 邏輯 封裝 supported dbms

  隔離級別越高,越能保證數據的完整性和一致性,但是對並發性能的影響也越大。對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed。它能夠避免臟讀取,而且具有較好的並發性能。盡管它會導致不可重復讀、幻讀和第二類丟失更新這些並發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。

數據庫的幾種隔離級別:

  • READ UNCOMMITTED(讀未提交數據):允許事務讀取未被其他事務提交的變更數據,會出現臟讀、不可重復讀和幻讀問題。
  • READ COMMITTED(讀已提交數據):只允許事務讀取已經被其他事務提交的變更數據,可避免臟讀,仍會出現不可重復讀和幻讀問題。
  • REPEATABLE READ(可重復讀):確保事務可以多次從一個字段中讀取相同的值,在此事務持續期間,禁止其他事務對此字段的更新,可以避免臟讀和不可重復讀,仍會出現幻讀問題。
  • SERIALIZABLE(序列化):確保事務可以從一個表中讀取相同的行,在這個事務持續期間,禁止其他事務對該表執行插入、更新和刪除操作,可避免所有並發問題,但性能非常低。

Oracle支持兩種事務隔離級別:

  READ COMMITTED(默認事務隔離級別),SERIALIZABLE

MySQL支持四種事務隔離級別,其中REPEATABLE READ為默認事務隔離級別。

通過上面可以知道多事務同時運行,如果不采用以上四種隔離機制,可能會產生多個並發問題,其中包括臟讀、不可重復讀和幻讀,下面就解釋下這幾種並發問題:

  存在兩個事物(T1,T2)同時運行

  • 臟讀:T1讀取了已經被T2修改但還未提交的字段,由於某種原因,T2事物回滾,則T1讀取的內容是臨時且無效的。
  • 不可重復讀:T1讀取一個字段,之後T2更新了該字段,T1在此讀取該字段值發生了變化。
  • 幻讀:T1從一個表中讀取了一個字段,然後T2在該表中插入了一些新的行,之後T1在此讀取該表會多出幾行。

二、數據庫事務的特性:原子性、一致性、隔離性、持久性

  • 原子性:事務的原子性指的是,事務中包含的程序作為數據庫的邏輯工作單位,它所做的對數據修改操作要麽全部執行,要麽完全不執行,這種特性稱為原子性。(簡單地說就是,幾個對於數據庫的操作要麽全執行,要麽全不執行,即同時成功起作用或同時失敗沒影響)
  • 一致性:事務一致性值得是在一個事務執行之前和執行之後數據庫都必須處於一致性狀態(中途是否一致不用管),這種特性稱為一致性。(如果數據庫的狀態滿足所有的完整性約束,就說該數據庫是一致的。一致性處理數據庫中對所有語義的保護。如:客戶K1要向客戶K2轉賬,K1賬戶減少的金額就是K2賬戶增加的金額,在轉賬之前K1和K2賬戶的金額之和與轉賬之後K1和K2賬戶的金額之和是一樣的,在轉賬期間可能不滿足這種一致性,但事務前後是數據庫數據是一致的)
  • 隔離性:隔離性指的是並發的事務是相互隔離的。(一個事務內部的操作及正在操作的數據必須封裝起來,不被其它企圖進行修改的事務看到)
  • 持久性:持久性指當系統或介質發生故障時,確保已提交的更新不能丟失。(一個事務提交,DBMS保證它對數據庫中數據的改變應該是永久性的,可以經受任何系統故障,持久性通過數據庫備份和恢復來保證)

三、傳播行為

  • PROPAGATION_REQUIRED:如果當前沒有事務,就創建一個新事務,如果當前存在事務,就加入該事務,該設置是最常用的設置。
  • PROPAGATION_SUPPORTS:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。‘
  • PROPAGATION_MANDATORY:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就拋出異常。
  • PROPAGATION_REQUIRES_NEW:創建新事務,無論當前存不存在事務,都創建新事務。
  • PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  • PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。
  • PROPAGATION_NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。
  • 1: PROPAGATION_REQUIRED
  • 加入當前正要執行的事務不在另外一個事務裏,那麽就起一個新的事務
  • 比如說,ServiceB.methodB的事務級別定義為PROPAGATION_REQUIRED, 那麽由於執行ServiceA.methodA的時候,
  • ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA
  • 的事務內部,就不再起新的事務。而假如ServiceA.methodA運行的時候發現自己沒有在事務中,他就會為自己分配一個事務。
  • 這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即使ServiceB.methodB的事務已經被
  • 提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾
  • 2: PROPAGATION_SUPPORTS
  • 如果當前在事務中,即以事務的形式運行,如果當前不再一個事務中,那麽就以非事務的形式運行
  • 3: PROPAGATION_MANDATORY
  • 必須在一個事務中運行。也就是說,他只能被一個父事務調用。否則,他就要拋出異常
  • 4: PROPAGATION_REQUIRES_NEW
  • 這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別為PROPAGATION_REQUIRED,ServiceB.methodB的事務級別為PROPAGATION_REQUIRES_NEW,
  • 那麽當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以後,
  • 他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。因為ServiceB.methodB是新起一個事務,那麽就是存在
  • 兩個不同的事務。如果ServiceB.methodB已經提交,那麽ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,
  • 如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
  • 5: PROPAGATION_NOT_SUPPORTED
  • 當前不支持事務。比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
  • 那麽當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
  • 6: PROPAGATION_NEVER
  • 不能在事務中運行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
  • 那麽ServiceB.methodB就要拋出異常了。
  • 7: PROPAGATION_NESTED
  • 理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
  • 而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最後回滾,他也要回滾的。
  • 而Nested事務的好處是他有一個savepoint。

數據庫事務4種隔離級別和7種傳播行為