SpringBoot整合事務

1。事務

事務(Transaction),一般是指要做的或所做的事情。在計算機的一個程式[執行單元]。事務通常由[高階資料庫]操縱語言或程式語言(如SQL,C++或Java)書寫的[使用者程式]的執行所引起,並用形如begin transaction和end transaction語句(或[函式呼叫])來界定。

1。1 事物的特性ACID

原子性(atomicity)。一個事務是一個不可分割的工作單位,事務中包括的操作要麼都做,要麼都不做。     【資料庫事務、資料庫設計第一正規化(原子性 唯一性  減少冗餘  適當冗餘 )、多執行緒特徵(原子性 可見性 有序性)】        一致性(consistency)。事務必須是使資料庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。            隔離性(isolation)。一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的資料對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。      永續性(durability)。永續性也稱永久性(permanence),指一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

1。2 全域性事務

全域性事務可以跨多個事務資源事務,如在一個分散式系統中的事務。

全域性事務(分散式事務):目前沒有很好的解決方案 TCC分段式提交、seta框架這兩個方法可以解決。

在實際專案中,全域性事務很少涉及到,因為沒有太多的強一致性操作。

1。3 區域性事務

特定於一個單一的事務資源,如一個 JDBC 連線。

spring對我們的事務操作進行了封裝 spring的事務分為兩種形式:程式設計式事務和宣告式事務 。

程式設計式事務: 自己使用 TransactionTemplate 在程式碼中 需要開啟事務的時候 建立事務 結束的時候提交事務。(程式設計師自己需要在每個方法中自己寫) 宣告式事務: 透過AOP在需要的方法開始之前 開啟事務 結束之後 提交事務

1。4 spring事務特性之事務的隔離級別

A、 事務隔離級別隔離級別是指若干個併發的事務之間的隔離程度。TransactionDefinition 介面中定義了五個表示隔離級別的常量:TransactionDefinition。ISOLATION_DEFAULT:這是預設值(預設讀已提交),表示使用底層資料庫的預設隔離級別。對大部分資料庫而言,通常這值就是TransactionDefinition。ISOLATION_READ_COMMITTED。TransactionDefinition。ISOLATION_READ_UNCOMMITTED:(讀未提交 一個事務能讀取另一個事務中沒有提交的資料)該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的資料。該級別不能防止髒讀,不可重複讀和幻讀,因此很少使用該隔離級別。比如PostgreSQL實際上並沒有此級別。TransactionDefinition。ISOLATION_READ_COMMITTED:(讀已提交)該隔離級別表示一個事務只能讀取另一個事務已經提交的資料。該級別可以防止髒讀,這也是大多數情況下的推薦值。TransactionDefinition。ISOLATION_REPEATABLE_READ:(重複讀 讀取的是快照)該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。該級別可以防止髒讀和不可重複讀。TransactionDefinition。ISOLATION_SERIALIZABLE:(事務之間依次執行 序列讀)所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。   在一次事務裡面,多次查詢之後,結果集的個數不一致的情況叫做幻讀。而多出來或者少的哪一行被叫做 幻行    不同隔離級別會有不同的問題:  髒讀 幻讀 不可重複讀

1。5 spring事務特性之事務的傳播行為

所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括瞭如下幾個表示傳播行為的常量:1) PROPAGATION_REQUIRED ,預設的spring事務傳播級別,使用該級別的特點是,如果上下文中已經存在事務,那麼就加入到事務中執行,如果當前上下文中不存在事務,則新建事務執行。所以這個級別通常能滿足處理大多數的業務場景。requiredv。 需要; 依靠; 依賴; 使做(某事); 使擁有(某物); (尤指根據法規)規定;2)PROPAGATION_SUPPORTS ,從字面意思就知道,supports,支援,該傳播級別的特點是,如果上下文存在事務,則支援事務加入事務,如果沒有事務,則使用非事務的方式執行。所以說,並非所有的包在transactionTemplate。execute中的程式碼都會有事務支援。這個通常是用來處理那些並非原子性的非核心業務邏輯操作。應用場景較少。supports v。 支援; 擁護; 鼓勵; 幫助; 援助; 資助; 贊助;3)PROPAGATION_MANDATORY , 該級別的事務要求上下文中必須要存在事務,否則就會丟擲異常!配置該方式的傳播級別是有效的控制上下文呼叫程式碼遺漏新增事務控制的保證手段。比如一段程式碼不能單獨被呼叫執行,但是一旦被呼叫,就必須有事務包含的情況,就可以使用這個傳播級別。mandatory adj。 強制的; 法定的; 義務的;4)PROPAGATION_REQUIRES_NEW ,從字面即可知道,new,每次都要一個新事務,該傳播級別的特點是,每次都會新建一個事務,並且同時將上下文中的事務掛起,執行當前新建事務完成以後,上下文事務恢復再執行。new adj。 剛出現的; 新的; 新近推出的; 新東西; 新事物; 新買的;這是一個很有用的傳播級別,舉一個應用場景:現在有一個傳送100個紅包的操作,在傳送之前,要做一些系統的初始化、驗證、資料記錄操作,然後傳送100封紅包,然後再記錄傳送日誌,傳送日誌要求100%的準確,如果日誌不準確,那麼整個父事務邏輯需要回滾。怎麼處理整個業務需求呢?就是透過這個PROPAGATION_REQUIRES_NEW 級別的事務傳播控制就可以完成。傳送紅包的子事務不會直接影響到父事務的提交和回滾。5)PROPAGATION_NOT_SUPPORTED ,這個也可以從字面得知,not supported ,不支援,當前級別的特點就是上下文中存在事務,則掛起事務,執行當前邏輯,結束後恢復上下文的事務。supported v。 支援; 擁護; 鼓勵; 幫助; 援助; 資助; 贊助;這個級別有什麼好處?可以幫助你將事務極可能的縮小。我們知道一個事務越大,它存在的風險也就越多。所以在處理事務的過程中,要保證儘可能的縮小範圍。比如一段程式碼,是每次邏輯操作都必須呼叫的,比如迴圈1000次的某個非核心業務邏輯操作。這樣的程式碼如果包在事務中,勢必造成事務太大,導致出現一些難以考慮周全的異常情況。所以這個事務這個級別的傳播級別就派上用場了。用當前級別的事務模板抱起來就可以了。6)PROPAGATION_NEVER ,該事務更嚴格,上面一個事務傳播級別只是不支援而已,有事務就掛起,而PROPAGATION_NEVER傳播級別要求上下文中不能存在事務,一旦有事務,就丟擲runtime異常,強制停止執行!這個級別上輩子跟事務有仇。7)PROPAGATION_NESTED ,字面也可知道,nested,巢狀級別事務。該傳播級別特徵是,如果上下文中存在事務,則巢狀事務執行,如果不存在事務,則新建事務。nestedv。 築巢; 巢居; 巢狀(資訊);那麼什麼是巢狀事務呢?很多人都不理解,我看過一些部落格,都是有些理解偏差。巢狀是子事務套在父事務中執行,子事務是父事務的一部分,在進入子事務之前,父事務建立一個回滾點,叫save point,然後執行子事務,這個子事務的執行也算是父事務的一部分,然後子事務執行結束,父事務繼續執行。重點就在於那個save point。看幾個問題就明瞭了:如果子事務回滾,會發生什麼?父事務會回滾到進入子事務前建立的save point,然後嘗試其他的事務或者其他的業務邏輯,父事務之前的操作不會受到影響,更不會自動回滾。如果父事務回滾,會發生什麼?父事務回滾,子事務也會跟著回滾!為什麼呢,因為父事務結束之前,子事務是不會提交的,我們說子事務是父事務的一部分,正是這個道理。那麼:事務的提交,是什麼情況?是父事務先提交,然後子事務提交,還是子事務先提交,父事務再提交?答案是第二種情況,還是那句話,子事務是父事務的一部分,由父事務統一提交。現在你再體會一下這個”巢狀“,是不是有那麼點意思?另外,事務常用的兩個屬性:readonly和timeout一個是設定事務為只讀以提升效能。另一個是設定事務的超時時間,一般用於防止大事務的發生。還是那句話,事務要儘可能的小!最後引入一個問題:一個邏輯操作需要檢查的條件有20條,能否為了減小事務而將檢查性的內容放到事務之外呢?很多系統都是在DAO的內部開始啟動事務,然後進行操作,最後提交或者回滾。這其中涉及到程式碼設計的問題。小一些的系統可以採用這種方式來做,但是在一些比較大的系統,邏輯較為複雜的系統中,勢必會將過多的業務邏輯嵌入到DAO中,導致DAO的複用性下降。所以這不是一個好的實踐。來回答這個問題:能否為了縮小事務,而將一些業務邏輯檢查放到事務外面?答案是:對於核心的業務檢查邏輯,不能放到事務之外,而且必須要作為分散式下的併發控制!一旦在事務之外做檢查,那麼勢必會造成事務A已經檢查過的資料被事務B所修改,導致事務A徒勞無功而且出現併發問題,直接導致業務控制失敗。所以,在分散式的高併發環境下,對於核心業務邏輯的檢查,要採用加鎖機制。比如事務開啟需要讀取一條資料進行驗證,然後邏輯操作中需要對這條資料進行修改,最後提交。這樣的一個過程,如果讀取並驗證的程式碼放到事務之外,那麼讀取的資料極有可能已經被其他的事務修改,當前事務一旦提交,又會重新覆蓋掉其他事務的資料,導致資料異常。所以在進入當前事務的時候,必須要將這條資料鎖住,使用for update就是一個很好的在分散式環境下的控制手段。一種好的實踐方式是使用程式設計式事務而非生命式,尤其是在較為規模的專案中。對於事務的配置,在程式碼量非常大的情況下,將是一種折磨,而且人肉的方式,絕對不能避免這種問題。將DAO保持針對一張表的最基本操作,然後業務邏輯的處理放入manager和service中進行,同時使用程式設計式事務更精確的控制事務範圍。特別注意的,對於事務內部一些可能丟擲異常的情況,捕獲要謹慎,不能隨便的catch Exception 導致事務的異常被吃掉而不能正常回滾。

1。6 spring事務特性之事務超時

所謂事務超時,就是指一個事務所允許執行的最長時間,如果超過該時間限制但事務還沒有完成,則自動回滾事務。 在TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。 預設設定為底層事務系統的超時值,如果底層資料庫事務系統沒有設定超時值,那麼就是none,沒有超時限制。

1。7 spring事務特性之事務只讀屬性

只讀事務用於客戶程式碼只讀但不修改資料的情形,只讀事務用於特定情景下的最佳化,比如使用Hibernate的時候。預設為讀寫事務。  “只讀事務”並不是一個強制選項,它只是一個“暗示”,提示資料庫驅動程式和資料庫系統,這個事務並不包含更改資料的操作,那麼JDBC驅動程式和資料庫就有可能根據這種情況對該事務進行一些特定的最佳化,比方說不安排相應的資料庫鎖,以減輕事務對資料庫的壓力,畢竟事務也是要消耗資料庫的資源的。 但是你非要在“只讀事務”裡面修改資料,也並非不可以,只不過對於資料一致性的保護不像“讀寫事務”那樣保險而已。 因此,“只讀事務”僅僅是一個性能最佳化的推薦配置而已,並非強制你要這樣做不可。      增刪改   查詢只讀 多個查詢執行的時候 沒必要加鎖

1。8 spring事務特性之事務回滾規則

指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內丟擲異常。spring事務管理器會捕捉任何未處理的異常,然後依據規則決定是否回滾丟擲異常的事務。預設配置下,spring只有在丟擲的異常為執行時unchecked異常時才回滾該事務,也就是丟擲的異常為RuntimeException的子類(Errors也會導致事務回滾),而丟擲checked異常則不會導致事務回滾。可以明確的配置在丟擲那些異常時回滾事務,包括checked異常。也可以明確定義那些異常丟擲時不回滾事務。還可以程式設計性的透過setRollbackOnly()方法來指示一個事務必須回滾,在呼叫完setRollbackOnly()後你所能執行的唯一操作就是回滾。

1。9 SpringBoot整合事務

在啟動類上 開啟事務@EnableTransactionManagement在需要事務的業務層方法上面 添加註解@Transactional此時我們詳細的瞭解這個註解@Target({ElementType。TYPE, ElementType。METHOD})@Retention(RetentionPolicy。RUNTIME)@Inherited@Documentedpublic @interface Transactional {    @AliasFor(“transactionManager”)    String value() default “”;    @AliasFor(“value”)    String transactionManager() default “”;    String[] label() default {};    Propagation propagation() default Propagation。REQUIRED;    Isolation isolation() default Isolation。DEFAULT;    int timeout() default -1;    String timeoutString() default “”;    boolean readOnly() default false;    Class<? extends Throwable>[] rollbackFor() default {};    String[] rollbackForClassName() default {};    Class<? extends Throwable>[] noRollbackFor() default {};    String[] noRollbackForClassName() default {};}@Transactional(timeout = 20,readOnly = true,isolation= Isolation。SERIALIZABLE ,propagation = Propagation。MANDATORY)

引用

https://www。cnblogs。com/wj0816/p/8474743。html

https://blog。csdn。net/sanyuesan0000/article/details/90235335

https://www。cnblogs。com/myseries/p/10748912。html