作者:YourBatman
原文連結:https://blog.csdn.net/f641385712/article/details/80445933
1、概述
事務在後端開發中無處不在,是資料一緻性的最基本保證。在Spring中可以通過對方法進行事務的配置,而不是像原來通過手動寫代碼的方式實作事務的操作,這在很大程度上減少了開發的難度。是以我們在使用spring事務的時候,門檻變得異常的低,國小生水準就能很好的管理好事務,但是同學們或多或少都遇見過一些事務不生效的難題,為啥呢?本文就針對于此來做一些具體舉例分析,盡量做到全覆寫。
2、栗子
Spring團隊建議在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實作的任何接口上。在接口上使用 @Transactional 注解,隻能當你設定了基于接口的代理時它才生效。因為注解是 不能繼承 的,這就意味着如果正在使用基于類的代理時,那麼事務的設定将不能被基于類的代理所識别,而且對象也将不會被事務代理所包裝。
「原因一:」 是否是資料庫引擎設定不對造成的。比如我們最常用的mysql,引擎MyISAM,是不支援事務操作的。需要改成InnoDB才能支援
「原因二:」 入口的方法必須是public,否則事務不起作用(這一點由Spring的AOP特性決定的,理論上而言,不public也能切入,但spring可能是覺得private自己用的方法,應該自己控制,不應該用事務切進去吧)。另外private 方法, final 方法 和 static 方法不能添加事務,加了也不生效
「原因三:」 Spring的事務管理預設隻對出現運作期異常(java.lang.RuntimeException及其子類)進行復原(至于為什麼spring要這麼設計:因為spring認為Checked的異常屬于業務的,coder需要給出解決方案而不應該直接扔該架構)
「原因四:」 @EnableTransactionManagement // 啟注解事務管理,等同于xml配置方式的 備注:本系列所有博文的讨論都針對于springboot而不再對spring做說明。@EnableTransactionManagement 在springboot1.4以後可以不寫。架構在初始化的時候已經預設給我們注入了兩個事務管理器的Bean(JDBC的DataSourceTransactionManager和JPA的JpaTransactionManager ),其實這就包含了我們最常用的Mybatis和Hibeanate了。當然如果不是AutoConfig的而是自己自定義的,請使用該注解開啟事務
「原因五:」 請确認你的類是否被代理了(因為spring的事務實作原理為AOP,隻有通過代理對象調用方法才能被攔截,事務才能生效)
「原因六:」 請確定你的業務和事務入口在同一個線程裡,否則事務也是不生效的,比如下面代碼事務不生效:
「原因七:」 也是我最想要去講的一個原因:service方法中調用本類中的另一個方法,事務沒有生效。這裡我把當初儲存的幾張對比圖貢獻給大家參考,一目了然:
圖一:事務不生效:[email protected]的事務開啟 ,或者是基于接口的 或者是基于類的代理被建立。是以在同一個類中一個無事務的方法調用另一個有事務的方法,事務是不會起作用的(這就是業界老問題:類内部方法調用事務不生效的問題原因)。

圖二:事務生效
圖三:事務生效
圖四:事務生效
圖五:事務生效(稍微解釋一下,這裡雖然是方法内部調用,但是事務切入了addInfo方法,是以即使内部抛出異常,也是可以生效的)
圖六:事務不生效(準确的說這叫沒有事務)
圖七:事務生效。這裡必須說幾句:這是我們解決方法内部調用事務不生效的最常用方法之一:内部維護一個注入自己的Bean,然後使用這個屬性來調用方法。其實還有一種方法,那就是利用Aop上下文來擷取代理對象(((TestService)AopContext.currentProxy()).create(); ),然後通過代理對象來調用。這裡需要注意:Aop上下文spring預設是關閉的,需要手動開啟