我們都知道Spring給我們提供了很多抽象,比如我們在操作資料庫的過程中,它為我們提供了事務方面的抽象,讓我們可以非常友善的以事務方式操作資料庫。不管你用JDBC、Mybatis、Hibernate等任何一種方式操作資料庫,也不管你使用DataSource還是JTA的事務,Spring事務抽象管理都能很好的把他統一在一起。接下來看一下事務的抽象核心接口
PlatformTransactionManager是事務管理器接口
常見的事務管理器有以下幾種
DataSourceTransactionManager
HibernateTransactionManager
JtaTransactionManager
這些管理器都實作了PlatformTransactionManager中的三個接口,實作邏輯略有差别,但是對使用者來講差別不大
定義事務的一些參數:
一些事務的參數在TransactionDefinition.java中,詳情如下:
下面兩張圖對這些參數進行了說明:
7種事務傳播特性:

四種事務隔離級别:
在看事務隔離級别前需要先了解下什麼是髒讀、不可重複讀、幻讀
髒讀: 髒讀就是一個事物未送出的資料,被另外一個事務讀到了,顯然這種情況不可接受
不可重複讀: 不可重複讀是指在一個事務内,多次讀同一資料,前後讀取的結果不一緻。
幻讀: 事務A對表中的一個資料進行了修改,這種修改涉及到表中的全部資料行。同時事務B也修改了這個表中的資料,這種修改是向表中插入一行新資料。那麼就會發生操作事務A的使用者發現表中還存在沒有修改的資料行,就好像發生了幻覺一樣
知道了以上幾個概念,我們來看看隔離級别:
這裡我們可以看到,Spring并不是提供了所有的事務管理的實作,而是提供了标準的事務管理器的操作接口PlatformTransactionManager, 并且規範了其行為,具體的事務實作由各個平台自行實作。這就是Spring的事務抽象。
Spring提供了TransactionTemplate工具類可以很友善的使用程式設計式事務。預設情況下TransactionTemplate使用的是DataSourceTransactionManager。
在Spring上下文中,我們不配置TransactionTemplate這個bean,也能擷取到TransactionTemplate。比如下面的例子。
由于Spring預設的事務傳播特性是PROPAGATION_REQUIRED,我們來做一下驗證,看是不是這樣
上面兩幅圖可以看出,TransactionStatus中的newTransaction屬性,第一個是true,第二個是false,正好符合PROPAGATION_REQUIRED所描述的情況。其他的傳播特性可以自己去驗證。
除了程式設計式事務外,Spring還為我們提供了聲明式事務。使用@Transactional注解。
@Transactional 可以作用于接口、接口方法、類以及類方法上。當作用于類上時,該類的所有 public 方法将都具有該類型的事務屬性,同時,我們也可以在方法級别使用該注解來覆寫類級别的定義。
雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這隻有在使用基于接口的代理時它才會生效。另外, @Transactional 注解應該隻被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者預設可見性的方法上使用 @Transactional 注解,這将被忽略,也不會抛出任何異常。
@Transactional的rollbackFor屬性可以設定一個 Throwable 的數組,用來表明如果方法抛出這些異常,則進行事務復原。預設情況下如果不配置rollbackFor屬性,那麼事務隻會在遇到RuntimeException的時候才會復原。
下面的代碼事務就不會生效:
如果我們把抛出的異常改成RuntimeException,這時候事務就會生效了。或者指定異常讓事務生效,比如 @Transactional(rollbackFor = Exception.class),這樣碰到所有的異常事務都會生效了。
這是因為Spring容器會為加了這個注解的對象生成一個代理對象,實際調用的時候,實際上是調用的代理對象。 代理對象的實作了AOP的增強,實作了事務的實作。
代碼中可以看出,我們可以指定隔離級别和傳播特性,在Spring為我們生成代理類的時候,會讀取這些屬性,展現在增強邏輯中。
這裡以 MySQL 為例,其 MyISAM 引擎是不支援事務操作的,InnoDB 才是支援事務的引擎,一般要支援事務都會使用 InnoDB,這時候選擇支援事務的資料庫即可(好像是廢話,哈哈哈)
這個好像沒什麼可說的,脫離了Spring的管理,還談什麼Spring事務管理。
@Transactional 隻能用于 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式。
相當于沒開啟事務管理,如果不是Springboot情況需要進行如下操作。
如果是SpringBoot,在啟動類上直接加上注解@EnableTransactionManagement即可。
傳播特性配置成,Propagation.SUPPORTED或者Propagation.NOT_SUPPORTED,改成支援事務的傳播特性即可。
因為預設的異常類型是運作時異常,如果抛出了其他異常就不生效。
解決方式:
1、将異常改成運作時異常
2、指定異常進行事務復原,如:@Transactional(rollbackFor = Exception.class)
如果你代碼這麼寫,事務不生效:
解決辦法: 必須要抛出異常,否則Spring事務管理,不會走到復原邏輯
上述代碼不生效,因為内部調用不會涉及到代理類的調用,更不會有AOP的增強,是以不會生效。
解決辦法:
1、自注入
2、Spring上下文
3、擷取他的代理類,直接調用代理類
----------------------------END---------------------------
更多Spring相關知識,請關注我,各平台都是同一個ID