欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解Spring事務(wù)原理

 更新時(shí)間:2016年07月08日 16:31:23   作者:吳極心  
這篇文章主要帶領(lǐng)大家深入理解Spring事務(wù)原理,Spring事務(wù)的傳播屬性

一、事務(wù)的基本原理
Spring事務(wù)的本質(zhì)其實(shí)就是數(shù)據(jù)庫對事務(wù)的支持,沒有數(shù)據(jù)庫的事務(wù)支持,spring是無法提供事務(wù)功能的。對于純JDBC操作數(shù)據(jù)庫,想要用到事務(wù),可以按照以下步驟進(jìn)行:
 1.獲取連接 Connection con = DriverManager.getConnection()
 2.開啟事務(wù)con.setAutoCommit(true/false);
 3.執(zhí)行CRUD
 4.提交事務(wù)/回滾事務(wù) con.commit() / con.rollback();
 5.關(guān)閉連接 conn.close(); 

使用Spring的事務(wù)管理功能后,我們可以不再寫步驟 2 和 4 的代碼,而是由Spirng 自動(dòng)完成。
那么Spring是如何在我們書寫的 CRUD 之前和之后開啟事務(wù)和關(guān)閉事務(wù)的呢?解決這個(gè)問題,也就可以從整體上理解Spring的事務(wù)管理實(shí)現(xiàn)原理了。下面簡單地介紹下,注解方式為例子
 1.配置文件開啟注解驅(qū)動(dòng),在相關(guān)的類和方法上通過注解@Transactional標(biāo)識。
 2.spring 在啟動(dòng)的時(shí)候會(huì)去解析生成相關(guān)的bean,這時(shí)候會(huì)查看擁有相關(guān)注解的類和方法,并且為這些類和方法生成代理,并根據(jù)@Transaction的相關(guān)參數(shù)進(jìn)行相關(guān)配置注入,這樣就在代理中為我們把相關(guān)的事務(wù)處理掉了(開啟正常提交事務(wù),異?;貪L事務(wù))。
 3.真正的數(shù)據(jù)庫層的事務(wù)提交和回滾是通過binlog或者redo log實(shí)現(xiàn)的。 

二、Spring 事務(wù)的傳播屬性
所謂spring事務(wù)的傳播屬性,就是定義在存在多個(gè)事務(wù)同時(shí)存在的時(shí)候,spring應(yīng)該如何處理這些事務(wù)的行為。這些屬性在TransactionDefinition中定義,具體常量的解釋見下表:

三、數(shù)據(jù)庫隔離級別

臟讀:一事務(wù)對數(shù)據(jù)進(jìn)行了增刪改,但未提交,另一事務(wù)可以讀取到未提交的數(shù)據(jù)。如果第一個(gè)事務(wù)這時(shí)候回滾了,那么第二個(gè)事務(wù)就讀到了臟數(shù)據(jù)。
不可重復(fù)讀:一個(gè)事務(wù)中發(fā)生了兩次讀操作,第一次讀操作和第二次操作之間,另外一個(gè)事務(wù)對數(shù)據(jù)進(jìn)行了修改,這時(shí)候兩次讀取的數(shù)據(jù)是不一致的。
幻讀:第一個(gè)事務(wù)對一定范圍的數(shù)據(jù)進(jìn)行批量修改,第二個(gè)事務(wù)在這個(gè)范圍增加一條數(shù)據(jù),這時(shí)候第一個(gè)事務(wù)就會(huì)丟失對新增數(shù)據(jù)的修改。
總結(jié)
隔離級別越高,越能保證數(shù)據(jù)的完整性和一致性,但是對并發(fā)性能的影響也越大。 
大多數(shù)的數(shù)據(jù)庫默認(rèn)隔離級別為 Read Commited,比如 SqlServer、Oracle
少數(shù)數(shù)據(jù)庫默認(rèn)隔離級別為:Repeatable Read 比如: MySQL InnoDB

四、Spring中的隔離級別

五、事務(wù)的嵌套
通過上面的理論知識的鋪墊,我們大致知道了數(shù)據(jù)庫事務(wù)和spring事務(wù)的一些屬性和特點(diǎn),接下來我們通過分析一些嵌套事務(wù)的場景,來深入理解spring事務(wù)傳播的機(jī)制。
假設(shè)外層事務(wù) Service A 的 Method A() 調(diào)用 內(nèi)層Service B 的 Method B()
PROPAGATION_REQUIRED(spring 默認(rèn))
如果ServiceB.methodB() 的事務(wù)級別定義為 PROPAGATION_REQUIRED,那么執(zhí)行 ServiceA.methodA() 的時(shí)候spring已經(jīng)起了事務(wù),這時(shí)調(diào)用 ServiceB.methodB(),ServiceB.methodB() 看到自己已經(jīng)運(yùn)行在 ServiceA.methodA() 的事務(wù)內(nèi)部,就不再起新的事務(wù)。
假如 ServiceB.methodB() 運(yùn)行的時(shí)候發(fā)現(xiàn)自己沒有在事務(wù)中,他就會(huì)為自己分配一個(gè)事務(wù)。
這樣,在 ServiceA.methodA() 或者在 ServiceB.methodB() 內(nèi)的任何地方出現(xiàn)異常,事務(wù)都會(huì)被回滾。
PROPAGATION_REQUIRES_NEW
比如我們設(shè)計(jì) ServiceA.methodA() 的事務(wù)級別為 PROPAGATION_REQUIRED,ServiceB.methodB() 的事務(wù)級別為 PROPAGATION_REQUIRES_NEW。
那么當(dāng)執(zhí)行到 ServiceB.methodB() 的時(shí)候,ServiceA.methodA() 所在的事務(wù)就會(huì)掛起,ServiceB.methodB() 會(huì)起一個(gè)新的事務(wù),等待 ServiceB.methodB() 的事務(wù)完成以后,它才繼續(xù)執(zhí)行。
他與 PROPAGATION_REQUIRED 的事務(wù)區(qū)別在于事務(wù)的回滾程度了。因?yàn)?ServiceB.methodB() 是新起一個(gè)事務(wù),那么就是存在兩個(gè)不同的事務(wù)。如果 ServiceB.methodB() 已經(jīng)提交,那么 ServiceA.methodA() 失敗回滾,ServiceB.methodB() 是不會(huì)回滾的。如果 ServiceB.methodB() 失敗回滾,如果他拋出的異常被 ServiceA.methodA() 捕獲,ServiceA.methodA() 事務(wù)仍然可能提交(主要看B拋出的異常是不是A會(huì)回滾的異常)。
PROPAGATION_SUPPORTS
假設(shè)ServiceB.methodB() 的事務(wù)級別為 PROPAGATION_SUPPORTS,那么當(dāng)執(zhí)行到ServiceB.methodB()時(shí),如果發(fā)現(xiàn)ServiceA.methodA()已經(jīng)開啟了一個(gè)事務(wù),則加入當(dāng)前的事務(wù),如果發(fā)現(xiàn)ServiceA.methodA()沒有開啟事務(wù),則自己也不開啟事務(wù)。這種時(shí)候,內(nèi)部方法的事務(wù)性完全依賴于最外層的事務(wù)。
PROPAGATION_NESTED
現(xiàn)在的情況就變得比較復(fù)雜了, ServiceB.methodB() 的事務(wù)屬性被配置為 PROPAGATION_NESTED, 此時(shí)兩者之間又將如何協(xié)作呢? 
ServiceB#methodB 如果 rollback, 那么內(nèi)部事務(wù)(即 ServiceB#methodB) 將回滾到它執(zhí)行前的 SavePoint 而外部事務(wù)(即 ServiceA#methodA) 可以有以下兩種處理方式:

a、捕獲異常,執(zhí)行異常分支邏輯

 void methodA() { 

  try { 

   ServiceB.methodB(); 

  } catch (SomeException) { 

   // 執(zhí)行其他業(yè)務(wù), 如 ServiceC.methodC(); 

  } 

 } 

這種方式也是嵌套事務(wù)最有價(jià)值的地方, 它起到了分支執(zhí)行的效果, 如果 ServiceB.methodB 失敗, 那么執(zhí)行 ServiceC.methodC(), 而 ServiceB.methodB 已經(jīng)回滾到它執(zhí)行之前的 SavePoint, 所以不會(huì)產(chǎn)生臟數(shù)據(jù)(相當(dāng)于此方法從未執(zhí)行過), 這種特性可以用在某些特殊的業(yè)務(wù)中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都沒有辦法做到這一點(diǎn)。
b、外部事務(wù)回滾/提交 代碼不做任何修改, 那么如果內(nèi)部事務(wù)(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滾到它執(zhí)行之前的 SavePoint(在任何情況下都會(huì)如此), 外部事務(wù)(即 ServiceA#methodA) 將根據(jù)具體的配置決定自己是 commit 還是 rollback
另外三種事務(wù)傳播屬性基本用不到,在此不做分析。 

六、總結(jié)
對于項(xiàng)目中需要使用到事務(wù)的地方,我建議開發(fā)者還是使用spring的TransactionCallback接口來實(shí)現(xiàn)事務(wù),不要盲目使用spring事務(wù)注解,如果一定要使用注解,那么一定要對spring事務(wù)的傳播機(jī)制和隔離級別有個(gè)詳細(xì)的了解,否則很可能發(fā)生意想不到的效果。

相關(guān)文章

  • Java數(shù)據(jù)結(jié)構(gòu)之LinkedList從鏈表到實(shí)現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)之LinkedList從鏈表到實(shí)現(xiàn)

    LinkedList是Java中常用的數(shù)據(jù)結(jié)構(gòu)之一,實(shí)現(xiàn)了鏈表的特性,支持快速添加、刪除元素,可以用于實(shí)現(xiàn)隊(duì)列、棧、雙向隊(duì)列等數(shù)據(jù)結(jié)構(gòu)。LinkedList的內(nèi)部實(shí)現(xiàn)采用了雙向鏈表,其中每個(gè)節(jié)點(diǎn)都包含前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn)的引用,可以直接訪問鏈表的頭尾元素
    2023-04-04
  • Java并發(fā)編程之阻塞隊(duì)列詳解

    Java并發(fā)編程之阻塞隊(duì)列詳解

    這篇文章主要為大家詳細(xì)介紹了Java并發(fā)編程之阻塞隊(duì)列,什么是阻塞隊(duì)列?主要的阻塞隊(duì)列及其方法介紹,感興趣的小伙伴們可以參考一下
    2016-03-03
  • spring-boot整合ehcache實(shí)現(xiàn)緩存機(jī)制的方法

    spring-boot整合ehcache實(shí)現(xiàn)緩存機(jī)制的方法

    spring-boot是一個(gè)快速的集成框架,其設(shè)計(jì)目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。這篇文章主要介紹了spring-boot整合ehcache實(shí)現(xiàn)緩存機(jī)制,需要的朋友可以參考下
    2018-01-01
  • Jenkins節(jié)點(diǎn)配置實(shí)現(xiàn)原理及過程解析

    Jenkins節(jié)點(diǎn)配置實(shí)現(xiàn)原理及過程解析

    這篇文章主要介紹了Jenkins節(jié)點(diǎn)配置實(shí)現(xiàn)原理及過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java實(shí)現(xiàn)文本編譯器

    Java實(shí)現(xiàn)文本編譯器

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)文本編譯器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Java遞歸方法求5!的實(shí)現(xiàn)代碼

    Java遞歸方法求5!的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java遞歸方法求5!的實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2017-02-02
  • springboot集成redis存對象亂碼的問題及解決

    springboot集成redis存對象亂碼的問題及解決

    這篇文章主要介紹了springboot集成redis存對象亂碼的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 深入理解Java垃圾回收機(jī)制以及內(nèi)存泄漏

    深入理解Java垃圾回收機(jī)制以及內(nèi)存泄漏

    下面小編就為大家?guī)硪黄钊肜斫釰ava垃圾回收機(jī)制以及內(nèi)存泄漏。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給的大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-05-05
  • Java?垃圾回收超詳細(xì)講解記憶集和卡表

    Java?垃圾回收超詳細(xì)講解記憶集和卡表

    卡表就是記憶集的一種具體實(shí)現(xiàn),它定義了記憶集的記錄精度、與堆內(nèi)存的映射關(guān)系等。?關(guān)于卡表與記憶集的關(guān)系,不妨按照J(rèn)ava語言中HashMap與Map的關(guān)系來類比理解。記憶集是一種用于記錄從非收集區(qū)域指向收集區(qū)域的指針集合的抽象數(shù)據(jù)結(jié)構(gòu)
    2022-04-04
  • springboot+vue實(shí)現(xiàn)驗(yàn)證碼功能

    springboot+vue實(shí)現(xiàn)驗(yàn)證碼功能

    這篇文章主要為大家詳細(xì)介紹了springboot+vue實(shí)現(xiàn)驗(yàn)證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論