溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于Spring中的事務@Transactional知識點有哪些

發布時間:2021-11-18 16:43:05 來源:億速云 閱讀:163 作者:iii 欄目:開發技術

本篇內容介紹了“基于Spring中的事務@Transactional知識點有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

ACID,事務內的一組操作具有 原子性 、一致性、隔離性、持久性。

  • Atomicity(原子性):一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。

  • Consistency(一致性):在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。

  • Isolation(隔離性):數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。

  • Durability(持久性):事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。

為什么要使用事務?

就是一組操作中,存在著多個更新修改操作,并且要滿足事務的相關要求,所以就需要使用到事務。最常見的例子就是銀行兩個賬戶間的轉賬,包含的A扣款 、B到賬等多個操作,這些個操作需要具備事務的特性。比如說,要么A成功扣款,B也成功到賬;不能出現A扣款了,B沒到賬(原子性);也不能出現現在AB都處理成功了,后續又出現A賬戶的錢又增多了(持久性);也不能出現A賬號初始余額充足,兩個并發處理,導致出現余額為負的情況(隔離性)。

如何使用事務?

在spring中可以使用聲明性的注解事務,即在有需要使用的方法、類上,用@Transactional

修飾即可。修飾的方法、類就是這個事務的包裹區域。出現了對應的異常就會在AOP中觸發回滾。

默認的回滾是錯誤與運行異常,不包括檢驗異常。

基于Spring中的事務@Transactional知識點有哪些

rollbackFor參數支持用戶自行設置,例如可定義異常跟運行異常,如下所示;也支持自定義異常類

@Transactional(rollbackFor = { Exception.class, RuntimeException.class })

默認的事務傳播機制是Propagation.REQUIRED

事務的傳播本質確定好事務的限制區域,即哪些代碼是受到事務保護的,出現異??梢曰貪L。

細節點:

  • 代碼出現事務配置的異常,在事務內的會自動回滾;如果在對應的方法體內使用了try catch捕獲異常,異常沒有拋出去,那就不會回滾,需要手動回滾了。在catch語句中增加手動回滾的TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句

  • public 方法的事務才生效

事務的傳播帶來的幾種結果

  • 外層沒有事務的話,內在的子方法,沒有的就沒有;有事務的就會有事務,有事務的效果形同Propagation.REQUIRES_NEW,互相獨立,每個都是一個不同的新事務

  • 外層有事務的話,那這個整個方法都在一個事務的區域范圍內,內外任何一處回滾,都是整個回滾。但是Propagation.NESTED修飾的內部方法,可以單獨回滾掉自己這個內部方法,作為一個嵌入子事務所具有的獨特性。

  • 外層有還是沒有事務,Propagation.REQUIRES_NEW修飾的方法都是作為一個獨立的事務,自己獨立控制回滾與提交,與外層事務無關聯。

此處舉例的事務,指的是 默認值為 Propagation.REQUIRED的傳播行為,以及Propagation.NESTED的傳播行為。

兩個特例

  • 同一個類中有A、B兩個方法,A調用B方法。A沒事務,B有事務,B有異常時,回滾失敗


A沒事務A有事務
B沒事務沒有事務的效果 不分析事務生效,B的異常,可以讓整個A回滾
B有事務事務失效事務生效,同上 不分析

若是A/B在同一個類中,A方法有事務,B方法沒有事務,這個時候事務會生效,原因是異常傳導到了A方法中;

A方法沒事務,B方法有事務,A調用B方法。若是A/B在同一個類中,B方法事務失效。A/B在不同的類,B方法有事務效果。

原因分析:這是動態代理導致的,當要執行B方法的回滾時,此時A調用的B方法,不是動態代理的那個類,無法進行回滾。

  • A方法循環調用B方法,A方法有事務,B方法啟用新事務,B方法處理成功一條提交一條的數據;B方法遇到異常,有異常的那條回滾,不影響之前處理成功提交的數據。

從之前的推斷來看,Propagation.REQUIRES_NEW修飾的內部方法獨立一個新事務,跟外層沒有關系,其實是兩個事務了,外層事務回滾內存的也不會回滾;內層回滾也不影響外層事務。

但是實際結果還是有點不太一樣,若是A/B在不同類中,可以達到這個效果;同一個類的話,就會回滾失敗。跟上面AB方法調用的結果類似。

究其原因,還是由于使用了動態代理來進行事務AOP的,此時的B方法一旦觸發回滾就是事務回滾異常了。那么要想一個類中兩個方法間調用達到部分提交的效果,需要使用ApplicationContext 上下文對象獲取當前類對象,再進行調用;

// 使用 ApplicationContext 上下文對象獲取該對象;
@Autowired
private ApplicationContext applicationContext; 
CurrentClass classService = applicationContext.getBean(CurrentClass.class); 
//再用這個對象去調用同類的其他方法
classService.b();

總結: 事務的實現依賴于動態代理,因此在同一個類中使用了類的其他方法時,就需要額外注意了,只有使用動態代理的對象去調用方法時,才會有事務回滾的操作。

事務傳播屬性propagation

propagation 代表事務的傳播行為,默認值為 Propagation.REQUIRED,總共的屬性信息如下:

  • Propagation.REQUIRED:如果當前存在事務,則加入該事務,如果當前不存在事務,則創建一個新的事務。(默認傳播行為,一定會有一個事務)

( 也就是說如果A方法和B方法都添加了注解,在默認傳播模式下,A方法內部調用B方法,會把兩個方法的事務合并為一個事務 )

  • Propagation.SUPPORTS:如果當前存在事務,則加入該事務;如果當前不存在事務,則以非事務的方式繼續運行。(以當前是否有事務為標準,可以有事務,也可以沒有事務)

  • Propagation.MANDATORY:如果當前存在事務,則加入該事務;如果當前不存在事務,則拋出異常。(要求當前有事務,就能運行;沒有就會異常)

  • Propagation.REQUIRES_NEW:重新創建一個新的事務,如果當前存在事務,暫停當前的事務。

( 當類A中的 a 方法用默認Propagation.REQUIRED模式,類B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中調用 b方法操作數據庫,然而 a方法拋出異常后,b方法并沒有進行回滾,因為Propagation.REQUIRES_NEW會暫停 a方法的事務 )

  • Propagation.NOT_SUPPORTED:以非事務的方式運行,如果當前存在事務,暫停當前的事務。(以非事務的方式運行,當前有不報錯)

  • Propagation.NEVER:以非事務的方式運行,如果當前存在事務,則拋出異常。

  • Propagation.NESTED :如果當前存在事務,則嵌套事務內執行,如果不存在事務和 Propagation.REQUIRED 效果一樣。

( 也就是說如果A方法和B方法都添加了注解,在A默認傳播模式下,B方法加上采用 Propagation.NESTED模式,A方法內部調用B方法,A回滾,B也會回滾;但B回滾,A不會回滾

數據庫隔離級別

事務的隔離級別依賴于數據庫的隔離級別,mysql的默認隔離級別是可重復讀(repeatable read),對應的效果是在一個事務內重復讀取一個表中的數據,一直會是一樣的,并不會讀取到那些個此事務范圍內其他事務 未提交(臟讀)、已提交(不可重復讀)的修改記錄。

在對數據進行測試隔離級別時,需要先對數據庫進行一系列的設置,包括關閉自動提交、查看當前的隔離級別,相關命令如下所示:

//由于變量autocommit分會話系統變量與全局系統變量, Value的值為ON,表示autocommit開啟。
OFF表示autocommit關閉。
show session variables like 'autocommit';
show global variables like 'autocommit';
 
//關閉當前會話的自動提交
set session autocommit=0;
 
//開啟一個事務
start transaction; 
begin;   
 
//回滾
rollback;    
//提交事務
commot;
//查看當前的隔離級別   查看全局、當前會話的隔離級別
select @@tx_isolation;
SELECT @@global.tx_isolation, @@session.tx_isolation;
 
//設置當前會話的隔離級別為read uncommitted級別:
set session transaction isolation level read uncommitted;
 
//設置當前會話的隔離級別為read committed級別:
set session transaction isolation level read committed;
 
//設置當前會話的隔離級別為repeatable read級別:
set session transaction isolation level repeatable read;
 
//設置當前會話的隔離級別為serializable級別:
set session transaction isolation level serializable;
 
//展示連接id
select connection_id();
 
//數據庫超時設置查詢
show session variables like '%timeout';

事務的隔離級別總共分為:未提交讀(read uncommitted)、已提交讀(read committed)、可重復讀(repeatable read)、串行化(serializable)。

下面將對這四種一一展開說明:

1、未提交讀(會有臟讀的現象)

A事務已執行,但未提交;B事務查詢到A事務的更新后數據;A事務回滾;那么之前讀取到的A事務為提交的數據就是臟數據了。最低的隔離級別,很少會使用到。

---臟讀,讀取到了未提交的數據(新增、修改和刪除); 除此之外,還有會不可重復讀、幻讀的現象。

基于Spring中的事務@Transactional知識點有哪些

事務1設置如上所示,隔離級別為讀未提交,關閉了自動提交。此時開始一個事務,看到的有兩條數據;

基于Spring中的事務@Transactional知識點有哪些

再打開一個窗口,關閉自動提交,然后進行新增改的操作

基于Spring中的事務@Transactional知識點有哪些

最后的結果如上所示,事務1讀取到了另一事務未提交時的新增、修改跟刪除的數據。

2、已提交讀

(會有不能重復讀的現象,因為每次讀取都是讀最新的,那就可能前后兩次會有差異了)

會讀取這一段時間內其他事務對這些數據的變更操作,A事務執行更新;B事務查詢;A事務又執行更新;B事務再次查詢時,B事務前后兩次查詢到的數據不一致;例如事務B要更新狀態,因此先進行一次查詢,此時狀態為1,一系列操作后,馬上就要更新了,此時再次查詢,第二次查詢出來的狀態變成了2。

---不可重復讀,一般指的是刪除、更新、新增;還會有幻讀的現象

基于Spring中的事務@Transactional知識點有哪些

不可重復讀的結果就是事務1能夠讀取到另外事務的 新增、修改、刪除操作,與臟讀的區別在于,一個是提交后才能讀取到,一個是未提交的實時操作就能讀取到。

3、可重復讀 (有可能覆蓋掉其他事務的操作)

可重復讀是mysql數據的默認隔離級別,也是使用的較多的一種隔離級別,下面重點對其分析分析。

A事務無論執行多少次,只要不提交,在這事務內同一個SQL的查詢值永遠都不變;可以理解成A事務內的所有查詢都是 查詢A事務開始時那一瞬間的數據快照;

幻讀: 由于互相隔離,以及可重復讀的特性,另一個事務也同時在處理同一數據的話,就會有一種空幻的現象,好像少了點什么。例如,兩個事務都帶id去插入同一數據,那么后插入的數據會加鎖執行失?。硪皇聞瘴刺峤唬┗蛘咧麈I沖突(另一事務已提交),而插入失敗后再去查詢,又會發現并沒有找到重復那條數據的,就會有種讀到了空白的感覺,少讀取到了內容。 幻讀不僅是插入,更新、刪除也會有這樣的現象的。

現實的一個例子,就是離銀行還款日期之前,A去查看賬單表,獲取到了此次的賬單數據,求得了總和,根據賬單綜合就將賬單還清了,并且還再次查詢,顯示已經還清了。此時,A將本次的查詢,還款操作提交到數據庫,在開開心心下班前,突然心血來潮再次進行了查詢賬單操作,突然多了幾條消費記錄了,需要再次還款。A就感覺 提交事務前的查詢有點幻讀了,少了幾條數據。

基于Spring中的事務@Transactional知識點有哪些

事務1在另一個事務提交后,再對同樣的數據做修改 刪除 新增操作。

基于Spring中的事務@Transactional知識點有哪些

---幻讀,一般值的是新增;就是明明查詢不到這條數據,去新增時會報錯。

其實更新、刪除也會有的,例如更新同一條用id+status去更新是,后提交的會更新失敗,這一特性也可用來加鎖,即CAS來更新數據,這樣后操作的肯定就不會覆蓋前面的數據了。

已經被刪除的數據,此時去更新,也不會生效了,在這個事務內再次查詢還是刪除前的那個數據快照。

基于Spring中的事務@Transactional知識點有哪些

如果更新數據時只用id,存在并發修改的情況,那么后提交的必定覆蓋之前事務的更新操作。比如本來數據的狀態是1,事務2將數據狀態有1->2,而事務1看的的狀態還是1,事務1直接使用id更新的話,將數據的狀態變成了3。事務1以為是1->3 ,其實是由 2->3,中間的狀態2直接就被覆蓋了。因此高并發的更新,需要慎重。

幻讀總結: 很多對幻讀的解釋是,一個事務在查詢的同時,另一個事務插入了數據,然后前一個事務再次查詢就會發現多了幾條數據,這個現象是不存在的,如果出現了,那說明當前的隔離級別是讀已提交了。

可重復讀中的就是說同一個事務了多次查詢返回的數據肯定是一樣的,這是毋庸置疑的,這也是與讀已提交的區別。因此,只有在當前事務提交后,再次查詢才會刷新到另一事務的改變。

那么我理解的幻讀就是,在另一事務新增數據并提交后,此時的事務去新增同樣一條數據,會報錯的,而此時再去查詢又是查無數據,這種現象才是幻讀。

更新數據層面就是,事務2已經將數據的狀態改變提交了,事務1用舊的狀態作為條件去更新,影響行數會是0,這也是一種幻讀。 更新已經被刪除的數據,也是影響行數為0。

數據庫最終的執行還是串行的,只是在前置的一些操作可以并發,最終更新到數據庫,只能是有一條成功,由于一些規則的設置,就會出現上述的現象了。

4、串行化(沒有并發操作)

串行化是最高的隔離級別,即事務排隊串行執行了,沒有了并發操作,也不會發生上述所說的臟讀、不可重復讀、幻讀的現象,這個的使用場景不多,理解起來也較為的簡單。

總結: 數據庫的隔離級別就是一個事務內,對于另一事務的并發操作會有怎么樣的效果;

  • 另一事務操作時就能看到修改后的數據,就是讀未提交

  • 另一事務操作并提交后 能看到修改后的數據,就是讀已提交

  • 另一事務操作提交后,當前事務依舊看不到相應的修改,事務開始什么數據,事務結束也是讀取到同樣的數據,就是可重復讀

所有的事務都排隊依次執行了,一次只能有一個進行修改,沒有了并行,就是串行化

Spring事務隔離級別比數據庫事務隔離級別多一個default

除了上述的四個隔離級別,多出來 DEFAULT (默認)這是一個PlatfromTransactionManager默認的隔離級別,即使用數據庫默認的事務隔離級別。另外四個與JDBC的隔離級別相對應,可以顯性去指定其隔離級別。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持億速云。

“基于Spring中的事務@Transactional知識點有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女