Spring事務(wù)管理機(jī)制(轉(zhuǎn)載)

Spring事務(wù)機(jī)制主要包括聲明式事務(wù)和編程式事務(wù)麦萤,此處側(cè)重講解聲明式事務(wù),編程式事務(wù)在實(shí)際開發(fā)中得不到廣泛使用扁眯,僅供學(xué)習(xí)參考壮莹。

Spring聲明式事務(wù)讓我們從復(fù)雜的事務(wù)處理中得到解脫。使得我們再也無需要去處理獲得連接姻檀、關(guān)閉連接命满、事務(wù)提交和回滾等這些操作。再也無需要我們在與事務(wù)相關(guān)的方法中處理大量的try…catch…finally代碼施敢。我們在使用Spring聲明式事務(wù)時(shí)周荐,有一個(gè)非常重要的概念就是事務(wù)屬性。事務(wù)屬性通常由事務(wù)的傳播行為僵娃,事務(wù)的隔離級(jí)別概作,事務(wù)的超時(shí)值和事務(wù)只讀標(biāo)志組成。我們在進(jìn)行事務(wù)劃分時(shí)默怨,需要進(jìn)行事務(wù)定義讯榕,也就是配置事務(wù)的屬性。

下面分別詳細(xì)講解匙睹,事務(wù)的四種屬性愚屁,僅供諸位學(xué)習(xí)參考:

Spring在TransactionDefinition接口中定義這些屬性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事務(wù)管理的核心接口。

public interface TransactionDefinition {
int getPropagationBehavior();//返回事務(wù)的傳播行為痕檬。
int getIsolationLevel();//返回事務(wù)的隔離級(jí)別霎槐,事務(wù)管理器根據(jù)它來控制另外一個(gè)事務(wù)可以看到本事務(wù)內(nèi)的哪些數(shù)據(jù)。
int getTimeout();//返回事務(wù)必須在多少秒內(nèi)完成梦谜。
boolean isReadOnly();//事務(wù)是否只讀丘跌,事務(wù)管理器能夠根據(jù)這個(gè)返回值進(jìn)行優(yōu)化袭景,確保事務(wù)是只讀的短绸。
}
  • TransactionDefinition接口中定義五個(gè)隔離級(jí)別:
    ISOLATION_DEFAULT 這是一個(gè)PlatfromTransactionManager默認(rèn)的隔離級(jí)別傍药,使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級(jí)別.另外四個(gè)與JDBC的隔離級(jí)別相對(duì)應(yīng)琐旁;

ISOLATION_READ_UNCOMMITTED 這是事務(wù)最低的隔離級(jí)別堆缘,它充許別外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數(shù)據(jù)。這種隔離級(jí)別會(huì)產(chǎn)生臟讀歹篓,不可重復(fù)讀和幻像讀母赵。

ISOLATION_READ_COMMITTED 保證一個(gè)事務(wù)修改的數(shù)據(jù)提交后才能被另外一個(gè)事務(wù)讀取眼溶。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)碍现。這種事務(wù)隔離級(jí)別可以避免臟讀出現(xiàn)幅疼,但是可能會(huì)出現(xiàn)不可重復(fù)讀和幻像讀。

ISOLATION_REPEATABLE_READ 這種事務(wù)隔離級(jí)別可以防止臟讀鸵赫,不可重復(fù)讀衣屏。但是可能出現(xiàn)幻像讀。它除了保證一個(gè)事務(wù)不能讀取另一個(gè)事務(wù)未提交的數(shù)據(jù)外辩棒,還保證了避免下面的情況產(chǎn)生(不可重復(fù)讀)。

ISOLATION_SERIALIZABLE 這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別膨疏。事務(wù)被處理為順序執(zhí)行一睁。除了防止臟讀,不可重復(fù)讀外佃却,還避免了幻像讀者吁。

1: Dirty reads(臟讀)。也就是說饲帅,比如事務(wù)A的未提交(還依然緩存)的數(shù)據(jù)被事務(wù)B讀走复凳,如果事務(wù)A失敗回滾,會(huì)導(dǎo)致事務(wù)B所讀取的的數(shù)據(jù)是錯(cuò)誤的灶泵。
2: non-repeatable reads(不可重復(fù)讀)育八。比如事務(wù)A中兩處讀取數(shù)據(jù)-total-的值。在第一讀的時(shí)候赦邻,total是100髓棋,然后事務(wù)B就把total的數(shù)據(jù)改成200,事務(wù)A再讀一次惶洲,結(jié)果就發(fā)現(xiàn)按声,total竟然就變成200了,造成事務(wù)A數(shù)據(jù)混亂恬吕。
3: phantom reads(幻讀)签则,這個(gè)和non-repeatable reads相似,也是同一個(gè)事務(wù)中多次讀不一致的問題铐料。但是non-repeatable reads的不一致是因?yàn)樗〉臄?shù)據(jù)集被改變了(比如total的數(shù)據(jù))渐裂,但是phantom reads所要讀的數(shù)據(jù)的不一致卻不是他所要讀的數(shù)據(jù)集改變侨颈,而是他的條件數(shù)據(jù)集改變。比如Select account.id where account.name=”ppgogo*”,第一次讀去了6個(gè)符合條件的id芯义,第二次讀取的時(shí)候哈垢,由于事務(wù)b把一個(gè)帳號(hào)的名字由”dd”改成”ppgogo1″,結(jié)果取出來了7個(gè)數(shù)據(jù)扛拨。

  • 在TransactionDefinition接口中定義了七個(gè)事務(wù)傳播行為:
    (1)PROPAGATION_REQUIRED 如果存在一個(gè)事務(wù)耘分,則支持當(dāng)前事務(wù)。如果沒有事務(wù)則開啟一個(gè)新的事務(wù)绑警。
//事務(wù)屬性 PROPAGATION_REQUIRED 
methodA{ 
…… 
methodB(); 
…… 
}
 
//事務(wù)屬性 PROPAGATION_REQUIRED 
methodB{ 
   …… 
}

使用spring聲明式事務(wù)求泰,spring使用AOP來支持聲明式事務(wù),會(huì)根據(jù)事務(wù)屬性计盒,自動(dòng)在方法調(diào)用之前決定是否開啟一個(gè)事務(wù)渴频,并在方法執(zhí)行之后決定事務(wù)提交或回滾事務(wù)。

單獨(dú)調(diào)用methodB方法:

main{ 
 
metodB(); 
 
}

相當(dāng)于

Main{ 
 
Connection con=null; 
 
try{ 
 
con = getConnection(); 
 
con.setAutoCommit(false); 
 
//方法調(diào)用
 
methodB(); 
 
//提交事務(wù)
 
con.commit(); 
 
} 
 
Catch(RuntimeException ex){ 
 
            //回滾事務(wù)
 
con.rollback();   
 
} 
 
finally{ 
 
//釋放資源
 
closeCon(); 
 
} 
 
}

Spring保證在methodB方法中所有的調(diào)用都獲得到一個(gè)相同的連接北启。在調(diào)用methodB時(shí)卜朗,沒有一個(gè)存在的事務(wù),所以獲得一個(gè)新的連接咕村,開啟了一個(gè)新的事務(wù)场钉。

單獨(dú)調(diào)用MethodA時(shí),在MethodA內(nèi)又會(huì)調(diào)用MethodB.

執(zhí)行效果相當(dāng)于:

         main{ 
 
Connection con = null; 
 
try{ 
 
con = getConnection(); 
 
    methodA(); 
 
con.commit(); 
 
} 
 
catch(RuntimeException ex){ 
 
con.rollback(); 
 
} 
 
finally{ 
 
   closeCon(); 
 
}  
 
}

調(diào)用MethodA時(shí)懈涛,環(huán)境中沒有事務(wù)逛万,所以開啟一個(gè)新的事務(wù).當(dāng)在MethodA中調(diào)用MethodB時(shí),環(huán)境中已經(jīng)有了一個(gè)事務(wù)批钠,所以methodB就加入當(dāng)前事務(wù)宇植。

(2)PROPAGATION_SUPPORTS 如果存在一個(gè)事務(wù),支持當(dāng)前事務(wù)埋心。如果沒有事務(wù)指郁,則非事務(wù)的執(zhí)行。但是對(duì)于事務(wù)同步的事務(wù)管理器踩窖,PROPAGATION_SUPPORTS與不使用事務(wù)有少許不同坡氯。

//事務(wù)屬性 PROPAGATION_REQUIRED 
methodA(){ 
  methodB(); 
}
 
//事務(wù)屬性 PROPAGATION_SUPPORTS 
methodB(){ 
  …… 
}

單純的調(diào)用methodB時(shí),methodB方法是非事務(wù)的執(zhí)行的洋腮。當(dāng)調(diào)用methdA時(shí),methodB則加入了methodA的事務(wù)中,事務(wù)地執(zhí)行箫柳。

(3)PROPAGATION_MANDATORY 如果已經(jīng)存在一個(gè)事務(wù),支持當(dāng)前事務(wù)啥供。如果沒有一個(gè)活動(dòng)的事務(wù)悯恍,則拋出異常。

//事務(wù)屬性 PROPAGATION_REQUIRED 
    methodA(){ 
  methodB(); 
                }
 
    //事務(wù)屬性 PROPAGATION_MANDATORY 
    methodB(){ 
    …… 
    }

當(dāng)單獨(dú)調(diào)用methodB時(shí)伙狐,因?yàn)楫?dāng)前沒有一個(gè)活動(dòng)的事務(wù)涮毫,則會(huì)拋出異常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);當(dāng)調(diào)用methodA時(shí)瞬欧,methodB則加入到methodA的事務(wù)中,事務(wù)地執(zhí)行罢防。

(4)PROPAGATION_REQUIRES_NEW 總是開啟一個(gè)新的事務(wù)艘虎。如果一個(gè)事務(wù)已經(jīng)存在,則將這個(gè)存在的事務(wù)掛起咒吐。

//事務(wù)屬性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
methodB(); 
doSomeThingB(); 
}
 
//事務(wù)屬性 PROPAGATION_REQUIRES_NEW 
methodB(){ 
   …… 
}
main(){ 
  methodA(); 
}

相當(dāng)于

main(){ 
  TransactionManager tm = null; 
try{ 
  //獲得一個(gè)JTA事務(wù)管理器 
    tm = getTransactionManager(); 
    tm.begin();//開啟一個(gè)新的事務(wù) 
    Transaction ts1 = tm.getTransaction(); 
    doSomeThing(); 
    tm.suspend();//掛起當(dāng)前事務(wù) 
    try{ 
      tm.begin();//重新開啟第二個(gè)事務(wù) 
      Transaction ts2 = tm.getTransaction(); 
      methodB(); 
      ts2.commit();//提交第二個(gè)事務(wù) 
   } 
  Catch(RunTimeException ex){ 
      ts2.rollback();//回滾第二個(gè)事務(wù) 
  } 
  finally{ 
     //釋放資源 
   } 
    //methodB執(zhí)行完后野建,復(fù)恢第一個(gè)事務(wù) 
    tm.resume(ts1); 
doSomeThingB(); 
    ts1.commit();//提交第一個(gè)事務(wù) 
} 
catch(RunTimeException ex){ 
   ts1.rollback();//回滾第一個(gè)事務(wù) 
} 
finally{ 
   //釋放資源 
} 
}

在這里,我把ts1稱為外層事務(wù)恬叹,ts2稱為內(nèi)層事務(wù)候生。從上面的代碼可以看出,ts2與ts1是兩個(gè)獨(dú)立的事務(wù)绽昼,互不相干唯鸭。Ts2是否成功并不依賴于ts1。如果methodA方法在調(diào)用methodB方法后的doSomeThingB方法失敗了硅确,而methodB方法所做的結(jié)果依然被提交目溉。而除了methodB之外的其它代碼導(dǎo)致的結(jié)果卻被回滾了。使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作為事務(wù)管理器疏魏。
(5)PROPAGATION_NOT_SUPPORTED 總是非事務(wù)地執(zhí)行停做,并掛起任何存在的事務(wù)。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務(wù)管理器大莫。(代碼示例同上,可同理推出)

(6)PROPAGATION_NEVER 總是非事務(wù)地執(zhí)行官份,如果存在一個(gè)活動(dòng)事務(wù)只厘,則拋出異常;

(7)PROPAGATION_NESTED如果一個(gè)活動(dòng)的事務(wù)存在舅巷,則運(yùn)行在一個(gè)嵌套的事務(wù)中. 如果沒有活動(dòng)事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行羔味。這是一個(gè)嵌套事務(wù),使用JDBC 3.0驅(qū)動(dòng)時(shí),僅僅支持DataSourceTransactionManager作為事務(wù)管理器。需要JDBC 驅(qū)動(dòng)的java.sql.Savepoint類钠右。有一些JTA的事務(wù)管理器實(shí)現(xiàn)可能也提供了同樣的功能赋元。使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設(shè)為true;而nestedTransactionAllowed屬性值默認(rèn)為false;

//事務(wù)屬性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
   methodB(); 
   doSomeThingB(); 
}
 
//事務(wù)屬性 PROPAGATION_NESTED 
methodB(){ 
  …… 
}

如果單獨(dú)調(diào)用methodB方法飒房,則按REQUIRED屬性執(zhí)行搁凸。如果調(diào)用methodA方法,相當(dāng)于下面的效果:

main(){ 
Connection con = null; 
Savepoint savepoint = null; 
try{ 
   con = getConnection(); 
   con.setAutoCommit(false); 
   doSomeThingA(); 
   savepoint = con2.setSavepoint(); 
   try{ 
       methodB(); 
   }catch(RuntimeException ex){ 
      con.rollback(savepoint); 
   } 
   finally{ 
     //釋放資源 
  }
 
   doSomeThingB(); 
   con.commit(); 
} 
catch(RuntimeException ex){ 
  con.rollback(); 
} 
finally{ 
   //釋放資源 
} 
}

當(dāng)methodB方法調(diào)用之前狠毯,調(diào)用setSavepoint方法护糖,保存當(dāng)前的狀態(tài)到savepoint。如果methodB方法調(diào)用失敗嚼松,則恢復(fù)到之前保存的狀態(tài)嫡良。但是需要注意的是锰扶,這時(shí)的事務(wù)并沒有進(jìn)行提交,如果后續(xù)的代碼(doSomeThingB()方法)調(diào)用失敗寝受,則回滾包括methodB方法的所有操作坷牛。

嵌套事務(wù)一個(gè)非常重要的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)。外層事務(wù)失敗時(shí)很澄,會(huì)回滾內(nèi)層事務(wù)所做的動(dòng)作京闰。而內(nèi)層事務(wù)操作失敗并不會(huì)引起外層事務(wù)的回滾。

PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區(qū)別:它們非常類似,都像一個(gè)嵌套事務(wù)痴怨,如果不存在一個(gè)活動(dòng)的事務(wù)忙干,都會(huì)開啟一個(gè)新的事務(wù)。使用PROPAGATION_REQUIRES_NEW時(shí)浪藻,內(nèi)層事務(wù)與外層事務(wù)就像兩個(gè)獨(dú)立的事務(wù)一樣捐迫,一旦內(nèi)層事務(wù)進(jìn)行了提交后,外層事務(wù)不能對(duì)其進(jìn)行回滾爱葵。兩個(gè)事務(wù)互不影響施戴。兩個(gè)事務(wù)不是一個(gè)真正的嵌套事務(wù)。同時(shí)它需要JTA事務(wù)管理器的支持萌丈。

使用PROPAGATION_NESTED時(shí)赞哗,外層事務(wù)的回滾可以引起內(nèi)層事務(wù)的回滾。而內(nèi)層事務(wù)的異常并不會(huì)導(dǎo)致外層事務(wù)的回滾辆雾,它是一個(gè)真正的嵌套事務(wù)肪笋。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED時(shí),需要JDBC 3.0以上驅(qū)動(dòng)及1.4以上的JDK版本支持度迂。其它的JTA TrasactionManager實(shí)現(xiàn)可能有不同的支持方式藤乙。

PROPAGATION_REQUIRES_NEW 啟動(dòng)一個(gè)新的, 不依賴于環(huán)境的 “內(nèi)部” 事務(wù). 這個(gè)事務(wù)將被完全 commited 或 rolled back 而不依賴于外部事務(wù), 它擁有自己的隔離范圍, 自己的鎖, 等等. 當(dāng)內(nèi)部事務(wù)開始執(zhí)行時(shí), 外部事務(wù)將被掛起, 內(nèi)務(wù)事務(wù)結(jié)束時(shí), 外部事務(wù)將繼續(xù)執(zhí)行。

另一方面, PROPAGATION_NESTED 開始一個(gè) “嵌套的” 事務(wù), 它是已經(jīng)存在事務(wù)的一個(gè)真正的子事務(wù). 潛套事務(wù)開始執(zhí)行時(shí), 它將取得一個(gè) savepoint. 如果這個(gè)嵌套事務(wù)失敗, 我們將回滾到此 savepoint. 潛套事務(wù)是外部事務(wù)的一部分, 只有外部事務(wù)結(jié)束后它才會(huì)被提交惭墓。

由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區(qū)別在于, PROPAGATION_REQUIRES_NEW 完全是一個(gè)新的事務(wù), 而 PROPAGATION_NESTED 則是外部事務(wù)的子事務(wù), 如果外部事務(wù) commit, 潛套事務(wù)也會(huì)被 commit, 這個(gè)規(guī)則同樣適用于 roll back.
PROPAGATION_REQUIRED應(yīng)該是我們首先的事務(wù)傳播行為坛梁。它能夠滿足我們大多數(shù)的事務(wù)需求。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腊凶,一起剝皮案震驚了整個(gè)濱河市划咐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钧萍,老刑警劉巖褐缠,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異划煮,居然都是意外死亡送丰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門弛秋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來器躏,“玉大人俐载,你說我怎么就攤上這事〉鞘В” “怎么了遏佣?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長揽浙。 經(jīng)常有香客問我状婶,道長,這世上最難降的妖魔是什么馅巷? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任膛虫,我火速辦了婚禮,結(jié)果婚禮上钓猬,老公的妹妹穿的比我還像新娘稍刀。我一直安慰自己,他們只是感情好敞曹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布账月。 她就那樣靜靜地躺著,像睡著了一般澳迫。 火紅的嫁衣襯著肌膚如雪局齿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天橄登,我揣著相機(jī)與錄音抓歼,去河邊找鬼。 笑死拢锹,一個(gè)胖子當(dāng)著我的面吹牛锭部,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播面褐,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼取胎!你這毒婦竟也來了展哭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤闻蛀,失蹤者是張志新(化名)和其女友劉穎匪傍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體觉痛,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡役衡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薪棒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片手蝎。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榕莺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棵介,到底是詐尸還是另有隱情钉鸯,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布邮辽,位于F島的核電站唠雕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吨述。R本人自食惡果不足惜岩睁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揣云。 院中可真熱鬧捕儒,春花似錦、人聲如沸灵再。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翎迁。三九已至栋猖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汪榔,已是汗流浹背蒲拉。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痴腌,地道東北人雌团。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像士聪,于是被迫代替她去往敵國和親锦援。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容