從Spring事務的隔離級別提及

隔離級別(isolation)定義了事務併發的隔離程度。數據庫

數據隔離級別分爲不一樣的四種:編程

  • Serializable :最嚴格的級別,事務串行執行,資源消耗最大;
  • REPEATABLE READ :保證了一個事務不會修改已經由另外一個事務讀取但未提交(回滾)的數據。避免了「髒讀取」和「不可重複讀取」的狀況,可是帶來了更多的性能損失。
  • READ COMMITTED :大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另外一個並行事務已修改但未提交的數據,避免了「髒讀取」。該級別適用於大多數系統。
  • Read Uncommitted :保證了讀取過程當中不會讀取到非法數據。

上面的解釋其實每一個定義都有一些拗口,其中涉及到幾個術語:髒讀、不可重複讀、幻讀。安全

這裏解釋一下:併發

  • 髒讀(Dirty reads)——髒讀發生在一個事務讀取了另外一個事務改寫但還沒有提交的數據時。若是改寫在稍後被回滾了,那麼第一個事務獲取的數據就是無效的。
  • 不可重複讀(Nonrepeatable read)——不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,可是每次都獲得不一樣的數據時。這一般是由於另外一個併發事務在兩次查詢期間進行了更新。
  • 幻讀(Phantom read)——幻讀與不可重複讀相似。它發生在一個事務(T1)讀取了幾行數據,接着另外一個併發事務(T2)插入了一些數據時。在隨後的查詢中,第一個事務(T1)就會發現多了一些本來不存在的記錄。

不可重複讀的重點是修改:分佈式

  • 一樣的條件, 你讀取過的數據, 再次讀取出來發現值不同了。

讀的重點在於新增或者刪除:高併發

  • 一樣的條件, 第1次和第2次讀出來的記錄數不同。

從控制的角度來看, 二者的區別就比較大:性能

  • 對於前者, 只須要鎖住知足條件的記錄。
  • 對於後者, 要鎖住知足條件及其相近的記錄。

一個對照關係表: Dirty reads non-repeatable reads phantom reads Serializable 不會 不會 不會 REPEATABLE READ 不會 不會 會 READ COMMITTED 不會 會 會 Read Uncommitted 會 會 會設計

因此最安全的,是Serializable,可是伴隨而來也是高昂的性能開銷。 另外,事務經常使用的兩個屬性:readonly和timeout 一個是設置事務爲只讀以提高性能。 另外一個是設置事務的超時時間,通常用於防止大事務的發生。仍是那句話,事務要儘量的小!事務

最後引入一個問題: 一個邏輯操做須要檢查的條件有20條,可否爲了減少事務而將檢查性的內容放到事務以外呢?資源

不少系統都是在DAO的內部開始啓動事務,而後進行操做,最後提交或者回滾。這其中涉及到代碼設計的問題。小一些的系統能夠採用這種方式來作,可是在一些比較大的系統, 邏輯較爲複雜的系統中,勢必會將過多的業務邏輯嵌入到DAO中,致使DAO的複用性降低。因此這不是一個好的實踐。

來回答這個問題:可否爲了縮小事務,而將一些業務邏輯檢查放到事務外面?

答案是:對於核心的業務檢查邏輯,不能放到事務以外,並且必需要做爲分佈式下的併發控制!

一旦在事務以外作檢查,那麼勢必會形成事務A已經檢查過的數據被事務B所修改,致使事務A徒勞無功並且出現併發問題,直接致使業務控制失敗。

因此,在分佈式的高併發環境下,對於核心業務邏輯的檢查,要採用加鎖機制。 好比事務開啓須要讀取一條數據進行驗證,而後邏輯操做中須要對這條數據進行修改,最後提交。 這樣的一個過程,若是讀取並驗證的代碼放到事務以外,那麼讀取的數據極有可能已經被其餘的事務修改,當前事務一旦提交,又會從新覆蓋掉其餘事務的數據,致使數據異常。 因此在進入當前事務的時候,必需要將這條數據鎖住,使用for update就是一個很好的在分佈式環境下的控制手段。

一種好的實踐方式是使用編程式事務而非生命式,尤爲是在較爲規模的項目中。對於事務的配置,在代碼量很是大的狀況下,將是一種折磨,並且人肉的方式,絕對不能避免這種問題。

將DAO保持針對一張表的最基本操做,而後業務邏輯的處理放入manager和service中進行,同時使用編程式事務更精確的控制事務範圍。 特別注意的,對於事務內部一些可能拋出異常的狀況,捕獲要謹慎,不能隨便的catch Exception 致使事務的異常被吃掉而不能正常回滾。

相關文章
相關標籤/搜索