1. 程式人生 > 實用技巧 >Spring關於事物的面試題

Spring關於事物的面試題

關於事物的面試題:
  事務是邏輯處理原子性的保證手段,通過使用事務控制,可以極大的避免出現邏輯處理失敗導致的髒資料等問題。
事務最重要的兩個特性,是事務的傳播級別和資料隔離級別。
1、傳播級別定義的是事務的控制範圍,
2、事務隔離級別定義的是事務在資料庫讀寫方面的控制範圍。

一、事物的七種傳播級別

1) PROPAGATION_REQUIRED ,預設的spring事務傳播級別,使用該級別的特點是,如果上下文中已經存在事務,
那麼就加入到事務中執行,如果當前上下文中不存在事務,則新建事務執行。所以這個級別通常能滿足處理大多數的業務場景。

2)PROPAGATION_SUPPORTS ,從字面意思就知道,supports,支援,該傳播級別的特點是,如果上下文存在事務,
則支援事務加入事務,如果沒有事務,則使用非事務的方式執行。所以說,並非所有的包在transactionTemplate.execute中的
程式碼都會有事務支援。這個通常是用來處理那些並非原子性的非核心業務邏輯操作。應用場景較少。

3)PROPAGATION_MANDATORY , 該級別的事務要求上下文中必須要存在事務,否則就會丟擲異常!配置該方式的傳播級別是有效的控制
上下文呼叫程式碼遺漏新增事務控制的保證手段。比如一段程式碼不能單獨被呼叫執行,但是一旦被呼叫,就必須有事務包含的情況,
就可以使用這個傳播級別。

4)PROPAGATION_REQUIRES_NEW ,從字面即可知道,new,每次都要一個新事務,該傳播級別的特點是,每次都會新建一個事務,
並且同時將上下文中的事務掛起,執行當前新建事務完成以後,上下文事務恢復再執行。

這是一個很有用的傳播級別,舉一個應用場景:現在有一個傳送100個紅包的操作,在傳送之前,要做一些系統的初始化、驗證、資料記錄操作,
然後傳送100封紅包,然後再記錄傳送日誌,傳送日誌要求100%的準確,如果日誌不準確,那麼整個父事務邏輯需要回滾。
怎麼處理整個業務需求呢?就是通過這個PROPAGATION_REQUIRES_NEW 級別的事務傳播控制就可以完成。傳送紅包的子事務不會直接影響到
父事務的提交和回滾。

5)PROPAGATION_NOT_SUPPORTED ,這個也可以從字面得知,not supported ,不支援,當前級別的特點就是上下文中存在事務,
則掛起事務,執行當前邏輯,結束後恢復上下文的事務。

這個級別有什麼好處?可以幫助你將事務極可能的縮小。我們知道一個事務越大,它存在的風險也就越多。所以在處理事務的過程中,
要保證儘可能的縮小範圍。比如一段程式碼,是每次邏輯操作都必須呼叫的,比如迴圈1000次的某個非核心業務邏輯操作。
這樣的程式碼如果包在事務中,勢必造成事務太大,導致出現一些難以考慮周全的異常情況。所以這個事務這個級別的傳播級別就派上用場了。
用當前級別的事務模板抱起來就可以了。

6)PROPAGATION_NEVER ,該事務更嚴格,上面一個事務傳播級別只是不支援而已,有事務就掛起,而PROPAGATION_NEVER傳播級別要求
上下文中不能存在事務,一旦有事務,就丟擲runtime異常,強制停止執行!這個級別上輩子跟事務有仇。

7)PROPAGATION_NESTED ,字面也可知道,nested,巢狀級別事務。該傳播級別特徵是,如果上下文中存在事務,則巢狀事務執行,
如果不存在事務,則新建事務。

二、什麼是巢狀事務?


巢狀是子事務套在父事務中執行,子事務是父事務的一部分,在進入子事務之前,父事務建立一個回滾點,叫save point,然後執行子事務,
這個子事務的執行也算是父事務的一部分,然後子事務執行結束,父事務繼續執行。重點就在於那個save point。看幾個問題就明瞭了:

1)如果子事務回滾,會發生什麼?
父事務會回滾到進入子事務前建立的save point,然後嘗試其他的事務或者其他的業務邏輯,父事務之前的操作不會受到影響,更不會自動回滾。

2)如果父事務回滾,會發生什麼?
父事務回滾,子事務也會跟著回滾!為什麼呢,因為父事務結束之前,子事務是不會提交的,我們說子事務是父事務的一部分,正是這個道理。

3)事務的提交,是什麼情況?
是父事務先提交,然後子事務提交,還是子事務先提交,父事務再提交?答案是第二種情況,還是那句話,子事務是父事務的一部分,
由父事務統一提交。


三、資料隔離級別分為不同的四種


1、Serializable :最嚴格的級別,事務序列執行,資源消耗最大;

2、REPEATABLE_READ :保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的資料。避免了“髒讀取”和“不可重複讀取”的情況,
但是帶來了更多的效能損失。

3、READ_COMMITTED :大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的資料,避免了“髒讀取”。
該級別適用於大多數系統。

4、Read_Uncommitted :保證了讀取過程中不會讀取到非法資料。


四、髒讀、不可重複讀、幻讀

1、髒讀 : 所謂的髒讀,其實就是讀到了別的事務回滾前的髒資料。比如事務B執行過程中修改了資料X,在未提交前,事務A讀取了X,
而事務B卻回滾了,這樣事務A就形成了髒讀。

2、不可重複讀 :不可重複讀字面含義已經很明瞭了,比如事務A首先讀取了一條資料,然後執行邏輯的時候,事務B將這條資料改變了,
然後事務A再次讀取的時候,發現數據不匹配了,就是所謂的不可重複讀了。

3、幻讀 :小的時候數手指,第一次數十10個,第二次數是11個,怎麼回事?產生幻覺了?
幻讀也是這樣子,事務A首先根據條件索引得到10條資料,然後事務B改變了資料庫一條資料,導致也符合事務A當時的搜尋條件,
這樣事務A再次搜尋發現有11條資料了,就產生了幻讀。


五、一個對照關係表:

Dirty reads non-repeatable reads phantom reads
Serializable 不會 不會 不會
REPEATABLE READ 不會 不會 會
READ COMMITTED 不會 會 會
Read Uncommitted 會 會 會

所以最安全的,是Serializable,但是伴隨而來也是高昂的效能開銷。
另外,事務常用的兩個屬性:readonly和timeout
一個是設定事務為只讀以提升效能。
另一個是設定事務的超時時間,一般用於防止大事務的發生。還是那句話,事務要儘可能的小!

六、Spring配置宣告式事務

* 配置DataSource
* 配置事務管理器
* 事務的傳播特性
* 那些類那些方法使用事務

1、Spring配置檔案中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,無論哪種配置方式,
一般變化的只是代理機制這部分。

2、DataSource、TransactionManager這兩部分只是會根據資料訪問方式有所變化,比如使用Hibernate進行資料訪問 時,DataSource
實際為SessionFactory,TransactionManager的實現為 HibernateTransactionManager。

根據代理機制的不同,Spring事務的配置又有幾種不同的方式:

第一種方式:每個Bean都有一個代理

第二種方式:所有Bean共享一個代理基類

第三種方式:使用攔截器

第四種方式:使用tx標籤配置的攔截器

第五種方式:全註解