事務(wù)管理對(duì)于企業(yè)應(yīng)用來說是至關(guān)重要的朵纷,當(dāng)出現(xiàn)異常情況時(shí)熊赖,它也可以保證數(shù)據(jù)的一致性鼎文。
Spring事務(wù)管理的兩種方式
spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式喉脖。
編程式事務(wù)使用TransactionTemplate或者直接使用底層的PlatformTransactionManager狂票。對(duì)于編程式事務(wù)管理祖驱,spring推薦使用TransactionTemplate书闸。
聲明式事務(wù)是建立在AOP之上的紊选。其本質(zhì)是對(duì)方法前后進(jìn)行攔截啡捶,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個(gè)事務(wù)姥敛,在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。聲明式事務(wù)最大的優(yōu)點(diǎn)就是不需要通過編程的方式管理事務(wù)瞎暑,這樣就不需要在業(yè)務(wù)邏輯代碼中摻雜事務(wù)管理的代碼彤敛,只需在配置文件中做相關(guān)的事務(wù)規(guī)則聲明(或通過基于@Transactional注解的方式)忿偷,便可以將事務(wù)規(guī)則應(yīng)用到業(yè)務(wù)邏輯中。
顯然聲明式事務(wù)管理要優(yōu)于編程式事務(wù)管理臊泌,這正是spring倡導(dǎo)的非侵入式的開發(fā)方式鲤桥。聲明式事務(wù)管理使業(yè)務(wù)代碼不受污染,一個(gè)普通的POJO對(duì)象渠概,只要加上注解就可以獲得完全的事務(wù)支持茶凳。和編程式事務(wù)相比,聲明式事務(wù)唯一不足地方是播揪,它的最細(xì)粒度只能作用到方法級(jí)別贮喧,無法做到像編程式事務(wù)那樣可以作用到代碼塊級(jí)別。但是即便有這樣的需求猪狈,也存在很多變通的方法箱沦,比如,可以將需要進(jìn)行事務(wù)管理的代碼塊獨(dú)立為方法等等雇庙。
聲明式事務(wù)管理也有兩種常用的方式谓形,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解疆前。顯然基于注解的方式更簡(jiǎn)單易用寒跳,更清爽。
spring事務(wù)特性
spring所有的事務(wù)管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口竹椒。
其中TransactionDefinition接口定義以下特性:
事務(wù)隔離級(jí)別
隔離級(jí)別是指若干個(gè)并發(fā)的事務(wù)之間的隔離程度童太。TransactionDefinition 接口中定義了五個(gè)表示隔離級(jí)別的常量:
TransactionDefinition.ISOLATION_DEFAULT:這是默認(rèn)值,表示使用底層數(shù)據(jù)庫的默認(rèn)隔離級(jí)別胸完。對(duì)大部分?jǐn)?shù)據(jù)庫而言书释,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)修改但還沒有提交的數(shù)據(jù)赊窥。該級(jí)別不能防止臟讀爆惧,不可重復(fù)讀和幻讀,因此很少使用該隔離級(jí)別誓琼。比如PostgreSQL實(shí)際上并沒有此級(jí)別检激。
TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)只能讀取另一個(gè)事務(wù)已經(jīng)提交的數(shù)據(jù)肴捉。該級(jí)別可以防止臟讀腹侣,這也是大多數(shù)情況下的推薦值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級(jí)別表示一個(gè)事務(wù)在整個(gè)過程中可以多次重復(fù)執(zhí)行某個(gè)查詢齿穗,并且每次返回的記錄都相同傲隶。該級(jí)別可以防止臟讀和不可重復(fù)讀。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務(wù)依次逐個(gè)執(zhí)行窃页,這樣事務(wù)之間就完全不可能產(chǎn)生干擾跺株,也就是說复濒,該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀乒省。但是這將嚴(yán)重影響程序的性能巧颈。通常情況下也不會(huì)用到該級(jí)別。
事務(wù)傳播行為
所謂事務(wù)的傳播行為是指袖扛,如果在開始當(dāng)前事務(wù)之前砸泛,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為蛆封。在TransactionDefinition定義中包括了如下幾個(gè)表示傳播行為的常量:
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。
事務(wù)超時(shí)
所謂事務(wù)超時(shí)葫录,就是指一個(gè)事務(wù)所允許執(zhí)行的最長(zhǎng)時(shí)間着裹,如果超過該時(shí)間限制但事務(wù)還沒有完成,則自動(dòng)回滾事務(wù)米同。在 TransactionDefinition 中以 int 的值來表示超時(shí)時(shí)間骇扇,其單位是秒摔竿。
默認(rèn)設(shè)置為底層事務(wù)系統(tǒng)的超時(shí)值,如果底層數(shù)據(jù)庫事務(wù)系統(tǒng)沒有設(shè)置超時(shí)值少孝,那么就是none继低,沒有超時(shí)限制。
spring事務(wù)回滾規(guī)則
默認(rèn)配置下稍走,spring只有在拋出的異常為運(yùn)行時(shí)unchecked異常時(shí)才回滾該事務(wù)郁季,也就是拋出的異常為RuntimeException的子類(Errors也會(huì)導(dǎo)致事務(wù)回滾),而拋出checked異常則不會(huì)導(dǎo)致事務(wù)回滾钱磅∶瘟眩可以明確的配置在拋出哪些異常時(shí)回滾事務(wù),包括checked異常盖淡。也可以明確定義那些異常拋出時(shí)不回滾事務(wù)年柠。還可以編程性的通過setRollbackOnly()方法來指示一個(gè)事務(wù)必須回滾,在調(diào)用完setRollbackOnly()后你所能執(zhí)行的唯一操作就是回滾褪迟。
以MyBatis為例冗恨,基于注解的聲明式事務(wù)配置
1、添加tx名字空間
xmlns:tx="http://www.springframework.org/schema/tx"
2味赃、開啟事務(wù)的注解支持
<!-- 開啟事務(wù)控制的注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
3掀抹、MyBatis自動(dòng)參與到spring事務(wù)管理中,無需額外配置心俗,只要org.mybatis.spring.SqlSessionFactoryBean引用的數(shù)據(jù)源與DataSourceTransactionManager引用的數(shù)據(jù)源一致即可傲武。
4、使用@Transactional注解
@Transactional 可以作用于接口城榛、接口方法揪利、類以及類方法上。當(dāng)作用于類上時(shí)狠持,該類的所有 public 方法將都具有該類型的事務(wù)屬性疟位,同時(shí),我們也可以在方法級(jí)別使用該注解來覆蓋類級(jí)別的定義喘垂。
雖然 @Transactional 注解可以作用于接口甜刻、接口方法、類以及類方法上正勒,但是 Spring
建議不要在接口或者接口方法上使用該注解得院,因?yàn)檫@只有在使用基于接口的代理時(shí)它才會(huì)生效。另外昭齐, @Transactional 注解應(yīng)該只被應(yīng)用到
public 方法上尿招,這是由 Spring AOP 的本質(zhì)決定的。如果你在 protected阱驾、private 或者默認(rèn)可見性的方法上使用
@Transactional 注解就谜,這將被忽略,也不會(huì)拋出任何異常里覆。
以MyBatis為例丧荐,基于.xml文件的聲明式事務(wù)配置