7.5 Spring事務(wù)控制

在Spring學(xué)習(xí)的書中,AOP最常見的應(yīng)用場(chǎng)景就是事務(wù)管理了∏耄基于AOP的事務(wù)管理是聲明式事務(wù),原理就是在方法的啟動(dòng)前設(shè)置事務(wù)開啟氯析,在方法結(jié)束后提交事務(wù)亏较,如果當(dāng)中有異常拋出,則事務(wù)回滾掩缓。

Spring的事務(wù)一般放到service層進(jìn)行執(zhí)行雪情,所以該層的方法,如果是事務(wù)處理的你辣,不能手工try catch異常巡通,必須由AOP來管理這些異常,不然事務(wù)將不會(huì)起作用舍哄。

這個(gè)簡(jiǎn)單講一下基于Spring的事務(wù)控制宴凉,沒有很深入,不過應(yīng)付多數(shù)開發(fā)是綽綽有余了表悬。

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ú)法做到像編程式事務(wù)那樣可以作用到代碼塊級(jí)別。但是即便有這樣的需求孕索,也存在很多變通的方法逛艰,比如,可以將需要進(jìn)行事務(wù)管理的代碼塊獨(dú)立為方法等等搞旭。

聲明式事務(wù)管理也有兩種常用的方式散怖,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解肄渗。顯然基于注解的方式更簡(jiǎn)單易用镇眷,更清爽。

事務(wù)隔離級(jí)別

隔離級(jí)別是指若干個(gè)并發(fā)的事務(wù)之間的隔離程度翎嫡。TransactionDefinition 接口中定義了五個(gè)表示隔離級(jí)別的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:這是默認(rèn)值欠动,表示使用底層數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別。對(duì)大部分?jǐn)?shù)據(jù)庫(kù)而言惑申,通常這值就是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ù)庫(kù)事務(wù)系統(tǒng)沒有設(shè)置超時(shí)值酝润,那么就是none燎竖,沒有超時(shí)限制。

事務(wù)只讀屬性

只讀事務(wù)用于客戶代碼只讀但不修改數(shù)據(jù)的情形要销,只讀事務(wù)用于特定情景下的優(yōu)化构回,比如使用Hibernate的時(shí)候。
默認(rèn)為讀寫事務(wù)。

“只讀事務(wù)”并不是一個(gè)強(qiáng)制選項(xiàng)捐凭,它只是一個(gè)“暗示”拨扶,提示數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序和數(shù)據(jù)庫(kù)系統(tǒng),這個(gè)事務(wù)并不包含更改數(shù)據(jù)的操作茁肠,那么JDBC驅(qū)動(dòng)程序和數(shù)據(jù)庫(kù)就有可能根據(jù)這種情況對(duì)該事務(wù)進(jìn)行一些特定的優(yōu)化患民,比方說不安排相應(yīng)的數(shù)據(jù)庫(kù)鎖,以減輕事務(wù)對(duì)數(shù)據(jù)庫(kù)的壓力垦梆,畢竟事務(wù)也是要消耗數(shù)據(jù)庫(kù)的資源的匹颤。
但是你非要在“只讀事務(wù)”里面修改數(shù)據(jù),也并非不可以托猩,只不過對(duì)于數(shù)據(jù)一致性的保護(hù)不像“讀寫事務(wù)”那樣保險(xiǎn)而已印蓖。
因此,“只讀事務(wù)”僅僅是一個(gè)性能優(yōu)化的推薦配置而已京腥,并非強(qiáng)制你要這樣做不可

spring事務(wù)回滾規(guī)則

spring事務(wù)管理器回滾一個(gè)事務(wù)的推薦方法是在當(dāng)前事務(wù)的上下文內(nèi)拋出異常赦肃。spring事務(wù)管理器會(huì)捕捉任何未處理的異常,然后依據(jù)規(guī)則決定是否回滾拋出異常的事務(wù)公浪。

默認(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í)行的唯一操作就是回滾憔古。

上面講了這么多,都是概念性的淋袖,很多人開發(fā)中會(huì)很疑惑鸿市, 我也沒有寫事務(wù)的控制語(yǔ)句啊,怎么就實(shí)現(xiàn)事務(wù)了呢适贸,下面簡(jiǎn)單說一下灸芳。
Spring的基本配置參照8.Spring JdbcTemplate這一節(jié)

利用配置來完成事務(wù)控制

applicatonContext.xml配置事務(wù)

 <!-- 利用AOP配置事務(wù)處理 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">
        </property>
    </bean>
    <aop:config>
        <aop:pointcut id="bussinessService"
                      expression="execution(public * com.critc.service.*.*(..))" />
        <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" />
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="import*" propagation="REQUIRED" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

這一段代碼是聲明式事務(wù)配置的核心涝桅,共包括三部分拜姿,第一部分是定義事務(wù)管理器transactionManager,這個(gè)事務(wù)管理器有好多種冯遂,如果是跨數(shù)據(jù)庫(kù)的事務(wù)蕊肥,還會(huì)用到JTA。
第二段是利用AOP定義切入點(diǎn)execution(public * com.critc.service.*.*(..))
第三段是定義事務(wù)的傳播特性,這一塊如果深入講起來會(huì)非常非常復(fù)雜壁却,肯定會(huì)把多數(shù)人搞糊涂批狱。簡(jiǎn)單記住兩點(diǎn)就行,如果是增刪改展东,就是REQUIRED赔硫,如果是查詢就是read-only。其中有一個(gè)method name的開始方法盐肃,一般以add|update|delete|save|import 開頭的方法才啟用事務(wù)爪膊,可以對(duì)數(shù)據(jù)庫(kù)操作,其余只能是讀砸王。

StaffService.java

@Service
public class StaffService {
    @Autowired
    private StaffDao staffDao;

    public void add() {
        Staff staff = new Staff();
        staff.setName("JDBCTemplate");
        staffDao.add(staff);

        Staff staff2 = new Staff();
        staff2.setName("JDBCTemplate123456789");
        staffDao.add(staff2);
    }
}

TestService.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext.xml"})
public class TestService {
    @Autowired
    private StaffService staffService;

    @Test
    public void testAdd() {
        staffService.add();
    }
}

簡(jiǎn)單測(cè)試一下推盛,比如往表里寫數(shù)據(jù),一共 寫兩條記錄谦铃,第一條沒問題耘成,第二條會(huì)超長(zhǎng)(字段長(zhǎng)度設(shè)置為20)。
當(dāng)點(diǎn)擊執(zhí)行時(shí)會(huì)報(bào)錯(cuò):

事務(wù)報(bào)錯(cuò)

兩條記錄都沒有寫入數(shù)據(jù)庫(kù)驹闰,這就是一個(gè)事務(wù)瘪菌。只有所有操作都成功后才會(huì)統(tǒng)一提交。

只讀方法設(shè)置疮方。

比如我把StaffService里面的add方法改為doadd控嗜,然后執(zhí)行測(cè)試,會(huì)報(bào)以下錯(cuò)誤

只讀方法

提示該方法是只讀的骡显。開發(fā)中經(jīng)常會(huì)遇到類似錯(cuò)誤疆栏,一定要快速定位進(jìn)行改正。

利用注解來完成事務(wù)控制

StaffService2.java

@Service
public class StaffService2 {
    @Autowired
    private StaffDao staffDao;

    @Transactional
    public void add() {
        Staff staff = new Staff();
        staff.setName("JDBCTemplate");
        staffDao.add(staff);

        Staff staff2 = new Staff();
        staff2.setName("JDBCTemplate123456789");
        staffDao.add(staff2);
    }
}

在需要啟用事務(wù)的方法上加上@Transactional即可惫谤。
這種方式不推薦采用壁顶,主要是每個(gè)方法都需要單獨(dú)配置比較麻煩,一般開發(fā)都是采用xml全局配置溜歪。

基于Spring的事務(wù)在開發(fā)中更多的是開發(fā)約定若专,定義好類和方法的命名,才能更好的使用事務(wù)蝴猪,否則事務(wù)是不會(huì)發(fā)揮作用的调衰。事務(wù)是開發(fā)中最最核心的一部分,一定要清楚原理自阱,不能簡(jiǎn)單說AOP干什么嚎莉,就是處理事務(wù),原理是什么沛豌,不清楚趋箩,那就等于還不是不明白什么是事務(wù)。事物的隔離級(jí)別和傳播屬性,多數(shù)情況下是用不到的叫确,真要用到了再學(xué)也不晚跳芳。

源碼下載

本工程詳細(xì)源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市竹勉,隨后出現(xiàn)的幾起案子飞盆,更是在濱河造成了極大的恐慌,老刑警劉巖次乓,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桨啃,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡檬输,警方通過查閱死者的電腦和手機(jī)照瘾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丧慈,“玉大人析命,你說我怎么就攤上這事√幽” “怎么了鹃愤?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)完域。 經(jīng)常有香客問我软吐,道長(zhǎng),這世上最難降的妖魔是什么吟税? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任凹耙,我火速辦了婚禮,結(jié)果婚禮上肠仪,老公的妹妹穿的比我還像新娘肖抱。我一直安慰自己,他們只是感情好异旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布意述。 她就那樣靜靜地躺著,像睡著了一般吮蛹。 火紅的嫁衣襯著肌膚如雪荤崇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天潮针,我揣著相機(jī)與錄音术荤,去河邊找鬼。 笑死然低,一個(gè)胖子當(dāng)著我的面吹牛喜每,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雳攘,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼带兜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了吨灭?” 一聲冷哼從身側(cè)響起刚照,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喧兄,沒想到半個(gè)月后无畔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吠冤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年浑彰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拯辙。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郭变,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涯保,到底是詐尸還是另有隱情诉濒,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布夕春,位于F島的核電站未荒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏及志。R本人自食惡果不足惜片排,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望速侈。 院中可真熱鬧划纽,春花似錦、人聲如沸锌畸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)潭枣。三九已至比默,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盆犁,已是汗流浹背命咐。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谐岁,地道東北人醋奠。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓榛臼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親窜司。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沛善,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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

  • 很多人喜歡這篇文章,特此同步過來 由淺入深談?wù)搒pring事務(wù) 前言 這篇其實(shí)也要?dú)w納到《常識(shí)》系列中塞祈,但這重點(diǎn)又...
    碼農(nóng)戲碼閱讀 4,739評(píng)論 2 59
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理金刁,服務(wù)發(fā)現(xiàn),斷路器议薪,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • 事務(wù)有四個(gè)特性:ACID 原子性(Atomicity):事務(wù)是一個(gè)原子操作尤蛮,由一系列動(dòng)作組成。事務(wù)的原子性確保動(dòng)作...
    jiangmo閱讀 1,235評(píng)論 0 7
  • spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式斯议。 編程式事務(wù)管理使用TransactionTemplate...
    熊熊要更努力閱讀 248評(píng)論 0 0
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,826評(píng)論 6 342