最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring事務Propagation及其實現(xiàn)原理詳解

 更新時間:2018年02月05日 16:01:52   作者:那個天真的人  
這篇文章主要介紹了spring事務Propagation及其實現(xiàn)原理詳解,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

本文研究的主要是spring事務Propagation及其實現(xiàn)原理,具體介紹如下。

簡介

spring目前已是java開發(fā)的一個事實標準,這得益于它的便利、功能齊全、容易上手等特性。在開發(fā)過程當中,操作DB是非常常見的操作,而涉及到db,就會涉及到事務。事務在平時的開發(fā)過程當中,就算沒有注意到,程序正常執(zhí)行不會有副作用,但如果出現(xiàn)了異常,而又沒有處理好事務的話,可能就會出現(xiàn)意想不到的結果。spring在事務方面進行了各種操作的封裝,特別是聲明式事務的出現(xiàn),讓開發(fā)變得更加的舒心。spring對事務進行了擴展,支持定義多種傳播屬性,這也是本篇要說明的重點。

事務是什么

非嚴格的講,一個事務是多個操作的簡稱,這些操作要么全部生效,要么一個都不生效(相當于沒有執(zhí)行過),一個通用的操作流程簡化如下:

try{
 Connection conn = getConnection();
 // 執(zhí)行一些數(shù)據(jù)庫操作
}catch(Exception e){
  conn.rollback();
}finally{
 conn.close();
}

從以上代碼可以看出一些問題:

  • 太多無用的固定代碼
  • 如果一個請求需要調用多個服務接口,難以更精細的控制事務
  • 跨多種底層數(shù)據(jù)層,如jdbc,mybatis,hibernate,jta,難以統(tǒng)一編碼方式。

spring提供了聲明式事務,使得我們不用關注底層的具體實現(xiàn),屏蔽了多種不同的底層實現(xiàn)細節(jié),為了支持多種復雜業(yè)務對事務的精細控制,spring提供了事務的傳播屬性,結合聲明式事務,成就了一大事務利器。

spring事務傳播屬性示例分析

在TransactionDefinition類中,spring提供了6種傳播屬性,接下來分別用簡單示例來說明。

溫馨提醒:下文提到的加入當前事務,指的是底層使用同一個Connection,但是事務狀態(tài)對象是可以重新創(chuàng)建的,并不影響。文章提到的當前只存在一個事務,表示的是共用底層的一個Connection,而不在乎創(chuàng)建了多少個事務狀態(tài)對象(TransactionStatus)。

1、PROPAGATION_REQUIRED

說明: 如果當前已經(jīng)存在事務,那么加入該事務,如果不存在事務,創(chuàng)建一個事務,這是默認的傳播屬性值。

看一個小例子,代碼如下:

@Transactional
public void service(){
 serviceA();
 serviceB();
}

@Transactional
serviceA();
@Transactional
serviceB();

serviceA 和 serviceB 都聲明了事務,默認情況下,propagation=PROPAGATION_REQUIRED,整個service調用過程中,只存在一個共享的事務,當有任何異常發(fā)生的時候,所有操作回滾。

2、PROPAGATION_SUPPORTS

說明:如果當前已經(jīng)存在事務,那么加入該事務,否則創(chuàng)建一個所謂的空事務(可以認為無事務執(zhí)行)。

看一個小例子,代碼如下:

public void service(){
  serviceA();
  throw new RunTimeException();
}

@Transactional(propagation=Propagation.SUPPORTS)
serviceA();

serviceA執(zhí)行時當前沒有事務,所以service中拋出的異常不會導致 serviceA回滾。

再看一個小例子,代碼如下:

public void service(){
  serviceA();
}

@Transactional(propagation=Propagation.SUPPORTS)
serviceA(){
 do sql 1
 1/0;
 do sql 2
}

由于serviceA運行時沒有事務,這時候,如果底層數(shù)據(jù)源defaultAutoCommit=true,那么sql1是生效的,如果defaultAutoCommit=false,那么sql1無效,如果service有@Transactional標簽,serviceA共用service的事務(不再依賴defaultAutoCommit),此時,serviceA全部被回滾。

3、 PROPAGATION_MANDATORY

說明:當前必須存在一個事務,否則拋出異常。

看一個小例子,代碼如下:

public void service(){
  serviceB();
  serviceA();
}
serviceB(){
 do sql
}
@Transactional(propagation=Propagation.MANDATORY)
serviceA(){
 do sql 
}

這種情況執(zhí)行 service會拋出異常,如果defaultAutoCommit=true,則serviceB是不會回滾的,defaultAutoCommit=false,則serviceB執(zhí)行無效。

4、PROPAGATN_REQUIRES_NEW

說明:如果當前存在事務,先把當前事務相關內容封裝到一個實體,然后重新創(chuàng)建一個新事務,接受這個實體為參數(shù),用于事務的恢復。更直白的說法就是暫停當前事務(當前無事務則不需要),創(chuàng)建一個新事務。 針對這種情況,兩個事務沒有依賴關系,可以實現(xiàn)新事務回滾了,但外部事務繼續(xù)執(zhí)行。

看一個小例子,代碼如下:

@Transactional
public void service(){
 serviceB();
 try{
  serviceA();
 }catch(Exception e){
 }
}
serviceB(){
 do sql
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
serviceA(){
 do sql 1
 1/0; 
 do sql 2
}

當調用service接口時,由于serviceA使用的是REQUIRES_NEW,它會創(chuàng)建一個新的事務,但由于serviceA拋出了運行時異常,導致serviceA整個被回滾了,而在service方法中,捕獲了異常,所以serviceB是正常提交的。 注意,service中的try … catch 代碼是必須的,否則service也會拋出異常,導致serviceB也被回滾。

5、Propagation.NOT_SUPPORTED

說明:如果當前存在事務,掛起當前事務,然后新的方法在沒有事務的環(huán)境中執(zhí)行,沒有spring事務的環(huán)境下,sql的提交完全依賴于 defaultAutoCommit屬性值 。

看一個小例子,代碼如下:

@Transactional
public void service(){
  serviceB();
  serviceA();
}
serviceB(){
 do sql
}
@Transactional(propagation=Propagation.NOT_SUPPORTED)
serviceA(){
 do sql 1
 1/0;
 do sql 2
}

當調用service方法的時候,執(zhí)行到serviceA方法中的1/0代碼時,拋出了異常,由于serviceA處于無事務環(huán)境下,所以 sql1是否生效取決于defaultAutoCommit的值,當defaultAutoCommit=true時,sql1是生效的,但是service由于拋出了異常,所以serviceB會被回滾。

6、 PROPAGATION_NEVER

說明: 如果當前存在事務,則拋出異常,否則在無事務環(huán)境上執(zhí)行代碼。

看一個小例子,代碼如下:

public void service(){
 serviceB();
 serviceA();
}
serviceB(){
 do sql
}
@Transactional(propagation=Propagation.NEVER)
serviceA(){
 do sql 1
 1/0;
 do sql 2
}

上面的示例調用service后,若defaultAutoCommit=true,則serviceB方法及serviceA中的sql1都會生效。

7、 PROPAGATION_NESTED

說明: 如果當前存在事務,則使用 SavePoint 技術把當前事務狀態(tài)進行保存,然后底層共用一個連接,當NESTED內部出錯的時候,自行回滾到 SavePoint這個狀態(tài),只要外部捕獲到了異常,就可以繼續(xù)進行外部的事務提交,而不會受到內嵌業(yè)務的干擾,但是,如果外部事務拋出了異常,整個大事務都會回滾。

注意: spring配置事務管理器要主動指定 nestedTransactionAllowed=true,如下所示:

 <bean id="dataTransactionManager"
 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataDataSource" />
  <property name="nestedTransactionAllowed" value="true" />
 </bean>

看一個小例子,代碼如下:

@Transactional
public void service(){
 serviceA();
 try{
  serviceB();
 }catch(Exception e){
 }
}
serviceA(){
 do sql
}
@Transactional(propagation=Propagation.NESTED)
serviceB(){
 do sql1
 1/0;
 do sql2
}

serviceB是一個內嵌的業(yè)務,內部拋出了運行時異常,所以serviceB整個被回滾了,由于service捕獲了異常,所以serviceA是可以正常提交的。

再來看一個例子,代碼如下:

@Transactional
public void service(){
  serviceA();
  serviceB();
  1/0;
}
@Transactional(propagation=Propagation.NESTED)
serviceA(){
 do sql
}
serviceB(){
 do sql
}

由于service拋出了異常,所以會導致整個service方法被回滾。(這就是跟PROPAGATION_REQUIRES_NEW不一樣的地方了,NESTED方式下的內嵌業(yè)務會受到外部事務的異常而回滾。)

實現(xiàn)淺析

前面舉例說明了spring事務提供的幾種傳播屬性,用于滿足多種不同的業(yè)務需求,大家可以依業(yè)務而定。接著我們再來看看spring實現(xiàn)這些傳播屬性最重要的技術依賴是什么。本小節(jié)列舉 PROPAGATION_REQUIRES_NEW 和 Propagation.NESTED 分別進行簡要說明。

1、 PROPAGATION_REQUIRES_NEW 實現(xiàn)原理

如下的代碼調用:

@Transactional
public void service(){
 serviceB();
 try{
  serviceA();
 }catch(Exception e){
 }
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
serviceA(){
 do sql 1
 1/0;
 do sql 2
}
serviceB(){
 do sql
}

執(zhí)行原理圖如下:

a. 創(chuàng)建事務狀態(tài)對象,獲取一個新的連接,重置連接的 autoCommit,fetchSize,timeout等屬性

b. 把連接綁定到ThreadLocal變量

c. 掛起當前事務,把當前事務狀態(tài)對象,連接等信息封裝成一SuspendedResources對象,可用于恢復

d. 創(chuàng)建新的事務狀態(tài)對象,重新獲取新的連接,重置新連接的 autoCommit,fetchSize,timeout等屬性,同時,保存SuspendedResources對象,用于事務的恢復,把新的連接綁定到ThreadLocal變量(覆蓋操作)

e. 捕獲到異常,回滾ThreadLocal中的連接,恢復連接參數(shù),關閉連接,恢復SuspendedResources

f. 提交ThreadLocal變量中的連接(導致serviceB被提交),還原連接參數(shù),關閉連接,連接歸還數(shù)據(jù)源

所以程序執(zhí)行的結果就是 serviceA被回滾了,serviceB成功提交了。

2、 PROPAGATION_NESTED 實現(xiàn)原理

如下的代碼調用:

@Transactional
public void service(){
 serviceA();
 try{
   serviceB();
 }catch(Exception e){
 }
}
serviceA(){
 do sql
}
@Transactional(propagation=Propagation.NESTED)
serviceB(){
 do sql1
 1/0;
 do sql2
}

執(zhí)行原理圖如下:

a. 創(chuàng)建事務狀態(tài)對象,獲取一個新的連接,重置連接的 autoCommit,fetchSize,timeout等屬性

b. 把連接綁定到ThreadLocal變量

c. 標記使用當前事務狀態(tài)對象,獲取ThreadLocal連接對象,保存當前連接的SavePoint,用于異?;謴停藭r的SavePoint就是執(zhí)行完serviceA后的狀態(tài)

d. 捕獲到異常,使用c中的SavePoint進行事務回滾,也就是把狀態(tài)回滾到執(zhí)行serviceA后的狀態(tài),serviceB方法所有執(zhí)行不生效

e. 獲取ThreadLocal中的連接對象,提交事務,恢復連接屬性,關閉連接

其它

spring在底層數(shù)據(jù)源的基礎上,利用 ThreadLocal,SavePoint等技術點實現(xiàn)了多種事務傳播屬性,便于實現(xiàn)各種復雜的業(yè)務。只有理解了傳播屬性的原理才能更好的駕馭spring事務。Spring回滾事務依賴于對異常的捕獲,默認情況下,只有拋出RuntimeException和Error才會回滾事務,當然可以進行配置,更多信息可以查看 @Transactional 這個注解。

總結

spring的聲明式事務給我們帶來了極大的便利,為了用好這把利器,理解底層的原理還是有必要的,本篇只是spring事務的冰山一角,讀者可以在此基礎上自行深入探索。

以上就是本文關于spring事務Propagation及其實現(xiàn)原理詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關文章

  • 一文詳解Java屬性為什么不能是is開頭的boolean

    一文詳解Java屬性為什么不能是is開頭的boolean

    在Java實體類定義中,boolean類型的屬性命名常引發(fā)爭議,阿里巴巴Java開發(fā)手冊建議避免使用is作為布爾類型屬性的前綴,原因在于當實體類被序列化或反序列化時,基于JavaBean規(guī)范的框架可能會移除或忽略is,導致不一致的字段名,文中介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • Java實現(xiàn)計算器的代碼

    Java實現(xiàn)計算器的代碼

    這篇文章主要為大家介紹了Java實現(xiàn)計算器的詳細代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Java List集合去重的多種實現(xiàn)方法

    Java List集合去重的多種實現(xiàn)方法

    Java中List集合去重的多種方法,包括使用循環(huán)、HashSet、保持順序去重、contain方法去重等,注意在刪除元素時,直接操作會導致ConcurrentModificationException,應使用傳統(tǒng)for循環(huán)或倒序刪除
    2025-02-02
  • Springboot配置返回日期格式化五種方法詳解

    Springboot配置返回日期格式化五種方法詳解

    本文主要介紹了Springboot配置返回日期格式化五種方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • Java實現(xiàn)深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS)算法

    Java實現(xiàn)深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS)算法

    深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS)是兩種基本的圖搜索算法,可用于圖的遍歷、路徑搜索等問題。DFS采用棧結構實現(xiàn),從起點開始往深處遍歷,直到找到目標節(jié)點或遍歷完整個圖;BFS采用隊列結構實現(xiàn),從起點開始往廣處遍歷,直到找到目標節(jié)點或遍歷完整個圖
    2023-04-04
  • Java內部類知識匯總

    Java內部類知識匯總

    在Java中,在類內部可以定義成員變量與方法,還可以在類的內部定義類.這種在類的內部定義的類稱為內部類.而內部類所在的類稱為外部類.
    2018-03-03
  • 詳解MyBatis批量插入數(shù)據(jù)Mapper配置文件的寫法

    詳解MyBatis批量插入數(shù)據(jù)Mapper配置文件的寫法

    本篇文章主要介紹了詳解MyBatis批量插入數(shù)據(jù)Mapper文件的寫法,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • 使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細步驟

    使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細步驟

    這篇文章主要介紹了使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細步驟,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Java設計模式中的門面模式詳解

    Java設計模式中的門面模式詳解

    門面模式又叫外觀模式(Facade Pattern),主要用于隱藏系統(tǒng)的復雜性,并向客戶端提供了一個客戶端可以訪問系統(tǒng)的接口,本文通過實例代碼給大家介紹下java門面模式的相關知識,感興趣的朋友一起看看吧
    2022-09-09
  • MyBatis使用級聯(lián)操作解決lombok構造方法識別失敗問題

    MyBatis使用級聯(lián)操作解決lombok構造方法識別失敗問題

    這篇文章主要介紹了MyBatis使用級聯(lián)操作解決lombok構造方法識別失敗問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07

最新評論

衡东县| 乐平市| 铜鼓县| 体育| 博爱县| 承德市| 云安县| 乌兰察布市| 乐东| 宁陵县| 平塘县| 霸州市| 响水县| 兴山县| 乃东县| 江达县| 申扎县| 易门县| 远安县| 顺昌县| 岢岚县| 精河县| 盐亭县| 寿宁县| 孟连| 忻城县| 乌拉特中旗| 铜陵市| 金昌市| 湟中县| 金门县| 孟村| 普兰店市| 剑河县| 扎兰屯市| 拉孜县| 新疆| 尼玛县| 成安县| 锦州市| 海兴县|