亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于Spring中的事務@Transactional細節(jié)與易錯點、幻讀

 更新時間:2021年11月18日 14:54:17   作者:日常打BUG  
這篇文章主要介紹了基于Spring中的事務@Transactional細節(jié)與易錯點、幻讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

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

  • Atomicity(原子性):一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環(huán)節(jié)。事務在執(zhí)行過程中發(fā)生錯誤,會被恢復(Rollback)到事務開始前的狀態(tài),就像這個事務從來沒有執(zhí)行過一樣。
  • Consistency(一致性):在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規(guī)則,這包含資料的精確度、串聯(lián)性以及后續(xù)數據庫可以自發(fā)性地完成預定的工作。
  • Isolation(隔離性):數據庫允許多個并發(fā)事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發(fā)執(zhí)行時由于交叉執(zhí)行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。
  • Durability(持久性):事務處理結束后,對數據的修改就是永久的,即便系統(tǒng)故障也不會丟失。

為什么要使用事務?

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

如何使用事務?

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

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

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

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

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

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

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

細節(jié)點:

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

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

  • 外層沒有事務的話,內在的子方法,沒有的就沒有;有事務的就會有事務,有事務的效果形同Propagation.REQUIRES_NEW,互相獨立,每個都是一個不同的新事務
  • 外層有事務的話,那這個整個方法都在一個事務的區(qū)域范圍內,內外任何一處回滾,都是整個回滾。但是Propagation.NESTED修飾的內部方法,可以單獨回滾掉自己這個內部方法,作為一個嵌入子事務所具有的獨特性。
  • 外層有還是沒有事務,Propagation.REQUIRES_NEW修飾的方法都是作為一個獨立的事務,自己獨立控制回滾與提交,與外層事務無關聯(lián)。

此處舉例的事務,指的是 默認值為 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方法有事務效果。

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

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

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

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

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

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

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

事務傳播屬性propagation

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

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

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

  • Propagation.SUPPORTS:如果當前存在事務,則加入該事務;如果當前不存在事務,則以非事務的方式繼續(xù)運行。(以當前是否有事務為標準,可以有事務,也可以沒有事務)
  • Propagation.MANDATORY:如果當前存在事務,則加入該事務;如果當前不存在事務,則拋出異常。(要求當前有事務,就能運行;沒有就會異常)
  • Propagation.REQUIRES_NEW:重新創(chuàng)建一個新的事務,如果當前存在事務,暫停當前的事務。

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

  • Propagation.NOT_SUPPORTED:以非事務的方式運行,如果當前存在事務,暫停當前的事務。(以非事務的方式運行,當前有不報錯)
  • Propagation.NEVER:以非事務的方式運行,如果當前存在事務,則拋出異常。
  • Propagation.NESTED :如果當前存在事務,則嵌套事務內執(zhí)行,如果不存在事務和 Propagation.REQUIRED 效果一樣。

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

數據庫隔離級別

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

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

//由于變量autocommit分會話系統(tǒng)變量與全局系統(tǒng)變量, 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事務已執(zhí)行,但未提交;B事務查詢到A事務的更新后數據;A事務回滾;那么之前讀取到的A事務為提交的數據就是臟數據了。最低的隔離級別,很少會使用到。

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

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

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

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

2、已提交讀

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 快速掌握Java8中的Optional

    快速掌握Java8中的Optional

    Optional 是一個容器類,代表一個值存在或不存在,Optional并不是用來替換所有的null,而是為了在設計良好的API中更明確地表達可能缺失的值,這篇文章主要介紹了Java8的Optional及使用,需要的朋友可以參考下
    2023-07-07
  • Ubuntu16.04 64位下JDK1.7的安裝教程

    Ubuntu16.04 64位下JDK1.7的安裝教程

    這篇文章主要為大家詳細介紹了Ubuntu16.04 64位下JDK1.7的安裝教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 淺談Java響應式系統(tǒng)

    淺談Java響應式系統(tǒng)

    第一次聽到reactive這個詞還是在幾年前,偶然了解到了Rxjava這個項目,仿佛為我打開了一扇新的大門,Rxjava是ReactiveX的java實現,ReactiveX家族除了Rxjava還有RxJS, Rx.NET,RxScala等等。
    2021-06-06
  • spring boot上傳文件出錯問題如何解決

    spring boot上傳文件出錯問題如何解決

    這篇文章主要介紹了spring boot上傳文件出錯問題如何解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Java 實戰(zhàn)項目錘煉之樸素風格個人博客系統(tǒng)的實現流程

    Java 實戰(zhàn)項目錘煉之樸素風格個人博客系統(tǒng)的實現流程

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java+vue+Springboot+ssm+mysql+maven+redis實現一個樸素風格的個人博客系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • java實現簡單的學生信息管理系統(tǒng)代碼實例

    java實現簡單的學生信息管理系統(tǒng)代碼實例

    這篇文章主要介紹了java實現簡單的學生信息管理系統(tǒng),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java?stream流中peek用法簡單示例

    Java?stream流中peek用法簡單示例

    這篇文章主要給大家介紹了關于Java?stream流中peek用法的相關資料,Java Stream中的peek()方法也是用于查看每個元素,但不改變流的操作的方法,文中通過代碼介紹的需要的朋友可以參考下
    2023-12-12
  • SWT(JFace) 文本編輯器 實現代碼

    SWT(JFace) 文本編輯器 實現代碼

    SWT(JFace) 文本編輯器 實現代碼
    2009-06-06
  • 詳解@AliasFor注解的使用與注意事項

    詳解@AliasFor注解的使用與注意事項

    @AliasFor注解是在spring源碼當中提供的,見名知義,他是為了別名而自定義的注解,下面我們來看看它的使用與注意事項,感興趣的小伙伴可以了解一下
    2023-08-08
  • SpringBoot結合mybatis-plus實現分頁的項目實踐

    SpringBoot結合mybatis-plus實現分頁的項目實踐

    本文主要介紹了SpringBoot結合mybatis-plus實現分頁的項目實踐,主要基于MyBatis-Plus 自帶的分頁插件 PaginationInterceptor,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06

最新評論