Java Spring事務(wù)管理與@Transactional注解式事務(wù)詳解

  • spring事務(wù)管理是指在業(yè)務(wù)代碼在出現(xiàn)異常之后,對(duì)之前的操作進(jìn)行回滾,保證數(shù)據(jù)庫(kù)數(shù)據(jù)的一致性

  • 分為編程式事務(wù)管理,配置式,注解式

    • 編程式
    TransactionDefinition def = new DefaultTransactionDefinition();
    TransactionStatus status = transactionManager.getTransaction(def)
    try{
      businessLogic();
      transactionManager.commit(status);
    }
    catch(Exception ex) {
      transactionManager. rollback(status);
      throw ex;
    }
    
    • xml配置式
    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="create*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" />
      <tx:method name="delete*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" />
      <tx:method name="update*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" />
      <tx:method name="get*" propagation="REQUIRED" read-only="true" timeout="300" />
      <tx:method name="*" propagation="REQUIRED" read-only="true" timeout="300" />
    </tx:attributes>
    </tx:advice>
    
    <aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* com.mico.emptyspring.service.*ServiceA.*(..))" />
    <aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice" />
    </aop:config>
    
    • 注解式,配置文件上添加配置<tx:annotation-driven transaction-manager="txManager"/>,接著在service類或方法上添加@Transactional注解
  • 先偷個(gè)雞,事務(wù)注解可以放在控制器層嗎?

    • 可以,但是在spring-framework-reference.pdf文檔中有這樣一段話:
      <tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.這句話的意思是,<tx:annoation-driven/>只會(huì)查找和它在相同的應(yīng)用上下文文件[同一配置文件]中定義的bean上面的@Transactional注解,如果你把它放在Dispatcher的應(yīng)用上下文中,它只檢查控制器上的@Transactional注解,而不是你services上的@Transactional注解。所以org.springframework.web.servlet.DispatcherServletcontextConfigLocation屬性配置的xml中配置<tx:annotation-driven/>則spring只檢查控制器上的@Transactional注解,而不是你services上的@Transactional注解。但是,不推薦這么做,嘻嘻
  • @Transactional配置項(xiàng)

屬性 類型 描述
value String 可選的限定描述符,指定使用的事務(wù)管理器
propagation enum: Propagation 可選的事務(wù)傳播行為設(shè)置
isolation enum: Isolation 可選的事務(wù)隔離級(jí)別設(shè)置
readOnly boolean 讀寫或只讀事務(wù),默認(rèn)讀寫
timeout int (in seconds granularity) 事務(wù)超時(shí)時(shí)間設(shè)置
rollbackFor Class對(duì)象數(shù)組,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類數(shù)組
rollbackForClassName 類名數(shù)組,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
noRollbackFor Class對(duì)象數(shù)組,必須繼承自Throwable 不會(huì)導(dǎo)致事務(wù)回滾的異常類數(shù)組
noRollbackForClassName 類名數(shù)組,必須繼承自Throwable 不會(huì)導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
  • value主要用來指定不同的事務(wù)管理器;主要用來滿足在同一個(gè)系統(tǒng)中,存在不同的事務(wù)管理器。比如在Spring中,聲明了兩種事務(wù)管理器txManager1, txManager2.然后,用戶可以根據(jù)這個(gè)參數(shù)來根據(jù)需要指定特定的txManager.在一個(gè)系統(tǒng)中,需要訪問多個(gè)數(shù)據(jù)源或者多個(gè)數(shù)據(jù)庫(kù),則必然會(huì)配置多個(gè)事務(wù)管理器的

  • 臟讀,不可重復(fù)讀和幻象讀

    • Dirty reads--讀臟數(shù)據(jù)。也就是說,比如事務(wù)A的未提交(還依然緩存)的數(shù)據(jù)被事務(wù)B讀走,如果事務(wù)A失敗回滾,會(huì)導(dǎo)致事務(wù)B所讀取的的數(shù)據(jù)是錯(cuò)誤的。
    • non-repeatable reads--數(shù)據(jù)不可重復(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ù)混亂。
    • phantom reads--幻象讀數(shù)據(jù),這個(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ù)。
  • 事務(wù)的隔離級(jí)別:是指若干個(gè)并發(fā)的事務(wù)之間的隔離程度

    • @Transactional(isolation = Isolation.READ_UNCOMMITTED):讀取未提交數(shù)據(jù)(會(huì)出現(xiàn)臟讀, 不可重復(fù)讀) 基本不使用。
    • @Transactional(isolation = Isolation.READ_COMMITTED):讀取已提交數(shù)據(jù)(會(huì)出現(xiàn)不可重復(fù)讀和幻讀)大多數(shù)主流數(shù)據(jù)庫(kù)的默認(rèn)事務(wù)等級(jí),保證了一個(gè)事務(wù)不會(huì)讀到另一個(gè)并行事務(wù)已修改但未提交的數(shù)據(jù),避免了“臟讀取”。該級(jí)別適用于大多數(shù)系統(tǒng)。
    • @Transactional(isolation = Isolation.REPEATABLE_READ):可重復(fù)讀(會(huì)出現(xiàn)幻讀),保證了一個(gè)事務(wù)不會(huì)修改已經(jīng)由另一個(gè)事務(wù)讀取但未提交(回滾)的數(shù)據(jù)。避免了“臟讀取”和“不可重復(fù)讀取”的情況,但是帶來了更多的性能損失。
    • @Transactional(isolation = Isolation.SERIALIZABLE):最嚴(yán)格的級(jí)別,事務(wù)串行執(zhí)行,資源消耗最大;
  • 事務(wù)隔離級(jí)別和臟讀,幻象讀,不可重復(fù)讀

Isolation Dirty reads Non-repeatable reads Phantom reads
Serializable 不會(huì) 不會(huì) 不會(huì)
REPEATABLE READ 不會(huì) 不會(huì) 會(huì)
READ COMMITTED 不會(huì) 會(huì) 會(huì)
Read Uncommitted 會(huì) 會(huì) 會(huì)
  • 事務(wù)傳播屬性:如果在開始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為,即事務(wù)方法的嵌套調(diào)用會(huì)產(chǎn)生事務(wù)傳播

    • TransactionDefinition.PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。這是默認(rèn)值。
    • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
    • TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
    • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
    • TransactionDefinition.PROPAGATION_NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
    • TransactionDefinition.PROPAGATION_MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。
    • TransactionDefinition.PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運(yùn)行;如果當(dāng)前沒有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED。
    • REQUIRED_NEW和NESTED兩種不同的傳播機(jī)制的區(qū)別:
      • REQUIRED_NEW:內(nèi)部的事務(wù)獨(dú)立運(yùn)行,在各自的作用域中,可以獨(dú)立的回滾或者提交;而外部的事務(wù)將不受內(nèi)部事務(wù)的回滾狀態(tài)影響.啟動(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í)行.
      • NESTED:的事務(wù),基于單一的事務(wù)來管理,提供了多個(gè)保存點(diǎn)。這種多個(gè)保存點(diǎn)的機(jī)制允許內(nèi)部事務(wù)的變更觸發(fā)外部事務(wù)的回滾。如果外部事務(wù) commit, 嵌套事務(wù)也會(huì)被 commit;如果外部事務(wù) roll back, 嵌套事務(wù)也會(huì)被 roll back 。開始一個(gè) “嵌套的” 事務(wù), 它是已經(jīng)存在事務(wù)的一個(gè)真正的子事務(wù). 嵌套事務(wù)開始執(zhí)行時(shí), 它將取得一個(gè) savepoint. 如果這個(gè)嵌套事務(wù)失敗, 我們將回滾到此 savepoint. 嵌套事務(wù)是外部事務(wù)的一部分, 只有外部事務(wù)結(jié)束后它才會(huì)被提交
  • @Transactional 注意事項(xiàng)

    • 用在接口實(shí)現(xiàn)類或接口實(shí)現(xiàn)方法上,而不是接口類中,Spring 建議不要在接口或者接口方法上使用@Transactional注解,因?yàn)檫@只有在使用基于接口的代理時(shí)它才會(huì)生效
    • @Transactional 注解應(yīng)該只被應(yīng)用到 public 方法上,
      這是由 Spring AOP 的本質(zhì)決定的。如果你在 protected、private 或者默認(rèn)可見性的方法上使用 @Transactional 注解,這將被忽略,也不會(huì)拋出任何異常。
    • 將@Transactional放置在需要進(jìn)行事務(wù)管理的方法上,而不是不假思索的放置在接口實(shí)現(xiàn)類上( 接口中所有方法都需要進(jìn)行事務(wù)管理,但其實(shí)并不需要,如只讀的接口就不需要事務(wù)管理,但是 由于配置了@Transactional就需要AOP攔截及事務(wù)的處理,影響系統(tǒng)性能)
    • 方法上注解屬性會(huì)覆蓋類注解上的相同屬性,當(dāng)接口與接口中方法上同時(shí)帶有@Transactional注解時(shí),方法上的事務(wù)注解會(huì)覆蓋類上的注解
    • 用 spring 事務(wù)管理器,由spring來負(fù)責(zé)數(shù)據(jù)庫(kù)的打開,提交,回滾.默認(rèn)遇到運(yùn)行期例外(throw new RuntimeException(“注釋”);)會(huì)回滾,即遇到不受檢查(unchecked)的例外時(shí)回滾;而遇到需要捕獲的例外(throw new Exception(“注釋”);)不會(huì)回滾,即遇到受檢查的例外(就是非運(yùn)行時(shí)拋出的異常,編譯器會(huì)檢查到的異常叫受檢查例外或說受檢查異常)時(shí),需我們指定方式來讓事務(wù)回滾要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .如果讓unchecked例外不回滾:@Transactional(notRollbackFor=RunTimeException.class)
    • 默認(rèn)情況下,只有來自外部的方法調(diào)用才會(huì)被AOP代理捕獲,也就是,類內(nèi)部方法調(diào)用本類內(nèi)部的其他方法并不會(huì)引起事務(wù)行為,即使被調(diào)用方法使用@Transactional注解進(jìn)行修飾,如下
      • 前置條件:同一個(gè)類中方法,A方法無(wú)@Transactional 注解,B使用了
        • 同一個(gè)類中A 調(diào)用 B ;則外部調(diào)用A之后,B的事務(wù)是不會(huì)起作用的
        • 若是有上層(按照 Controller層、Service層、DAO層的順序)由Controller 調(diào)用 Service 直接調(diào)用B方法,發(fā)生異常會(huì)發(fā)生回滾;若間接調(diào)用,Action 調(diào)用 Service 中 的A 方法,A無(wú)@Transactional 注解,B有,A調(diào)用B,B的注解無(wú)效
    • 父類的聲明的@Transactional會(huì)對(duì)子類的所有方法進(jìn)行事務(wù)增強(qiáng);子類覆蓋重寫父類方式可覆蓋其@Transactional中的聲明配置
  • 多線程下事務(wù)管理

    • 因?yàn)榫€程不屬于spring托管,故線程不能夠默認(rèn)使用spring的事務(wù),也不能獲取spring注入的bean
    • 在被spring聲明式事務(wù)管理的方法內(nèi)開啟多線程,多線程內(nèi)的方法不被事務(wù)控制
    • 單線程的情況下,一個(gè)事務(wù)會(huì)在層級(jí)式調(diào)用的Spring組件之間傳播。但是在@Transactional注解的服務(wù)方法會(huì)產(chǎn)生一個(gè)新的線程的情況下,事務(wù)是不會(huì)從調(diào)用者線程傳播到新建線程的。結(jié)果會(huì)是被調(diào)用者線程會(huì)說缺少事務(wù),
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,690評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,019評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,188評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,438評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,667評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,845評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,384評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380