javascript
springaop事务逻辑原理_架构师:一篇文章掌握——Spring 事务管理
對大多數(shù)Java開發(fā)者來說,Spring事務(wù)管理是Spring應(yīng)用中最常用的功能,使用也比較簡單。本文主要逐步介紹Spring事務(wù)管理的相關(guān)知識(shí)點(diǎn)及原理,作為Spring事務(wù)管理的學(xué)習(xí)總結(jié)。
一、關(guān)鍵類
事務(wù)真正的開始、提交、回滾都是通過PlatformTransactionManager這個(gè)接口來實(shí)現(xiàn)的,例如,我們常用的org.springframework.jdbc.datasource.DataSourceTransactionManager。
TransactionDefinition用于獲取事務(wù)的一些屬性,Isolation, Propagation,Timeout,Read-only,還定義了事務(wù)隔離級(jí)別,傳播屬性等常量。
TransactionStatus用于設(shè)置和查詢事務(wù)的狀態(tài),如是否是新事務(wù),是否有保存點(diǎn),設(shè)置和查詢RollbackOnly等。
二、聲明式事務(wù)
所謂聲明式事務(wù),就是通過配置的方式省去很多代碼,從而讓Spring來幫你管理事務(wù)。本質(zhì)上就是配置一個(gè)Around方式的AOP,在執(zhí)行方法之前,用TransactionInterceptor截取,然后調(diào)用PlatformTransactionManager的某個(gè)實(shí)現(xiàn)做一些事務(wù)開始前的事情,然后在方法執(zhí)行后,調(diào)用PlatformTransactionManager的某個(gè)實(shí)現(xiàn)做commit或rollback. 如圖:
聲明式事務(wù)可以通過XML配置,也可以通過Annotation的方式來配置,還可以兩種結(jié)合。平時(shí)項(xiàng)目中看到比較多的是兩種結(jié)合的方式,在XML中配置數(shù)據(jù)源,事務(wù)管理器,然后AOP相關(guān)的通過@Transactional(該注解可以注在Class,Method上)來配置。(個(gè)人感覺,AOP相關(guān)的配置用XML配置挺繁瑣的,還是注解好)例如:
三、事務(wù)屬性
引用官方文檔的表格
(一)、value,在有多個(gè)事務(wù)管理器存在的情況下,用于標(biāo)識(shí)使用哪個(gè)事務(wù)管理器
(二)、isolation,事務(wù)的隔離級(jí)別,默認(rèn)是Isolation.DEFAULT,這個(gè)DEFAULT是和具體使用的數(shù)據(jù)庫相關(guān)的。關(guān)于隔離級(jí)別,可以參考MySQL事務(wù)學(xué)習(xí)總結(jié)
(三)、readOnly, 是否只讀,如果配置了true,但是方法里使用了update,insert語句,會(huì)報(bào)錯(cuò)。對于只讀的事務(wù),配置為true有助于提高性能。
(四)、rollbackFor, noRollbackFor. Spring的聲明式事務(wù)的默認(rèn)行為是如果方法拋出RuntimeException或者Error,則事務(wù)會(huì)回滾,對于其他的checked類型的異常,不會(huì)回滾。如果想改變這種默認(rèn)行為,可以通過這幾個(gè)屬性來配置。
(五)、propagation, 后面會(huì)具體講。
四、 事務(wù)的傳播機(jī)制
其他的都還好理解,后面結(jié)合例子重點(diǎn)介紹下PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED三種傳播級(jí)別。
表結(jié)構(gòu)和原始數(shù)據(jù):
(一)、PROPAGATION_REQUIRED
執(zhí)行完之后,test表的數(shù)據(jù)沒有任何變化。
由于MysqlTest02中的事務(wù)傳播類型是Propagation.REQUIRED,邏輯上有兩個(gè)事務(wù),但底層是共用一個(gè)物理事務(wù)的,第二個(gè)事務(wù)的拋出RuntimeExcetion導(dǎo)致事務(wù)回滾,對于這種傳播類型,內(nèi)層事務(wù)的回滾會(huì)導(dǎo)致外層事務(wù)回滾。所以數(shù)據(jù)庫中的數(shù)據(jù)沒有任何變化。
(二)、PROPAGATION_REQUIRES_NEW
同樣的代碼,唯一的區(qū)別就是第二個(gè)事務(wù)的傳播屬性改成了REQUIRES_NEW,執(zhí)行結(jié)果是啥?不好意思,第二個(gè)事務(wù)執(zhí)行不了。
對于REQUIRES_NEW,邏輯上有兩個(gè)事務(wù),底層物理上也有兩個(gè)事務(wù),由于第一個(gè)事務(wù)和第二個(gè)事務(wù)更新的是同一條記錄,對于Mysql默認(rèn)的隔離級(jí)別REPEATABLE-READ來說,第一個(gè)事務(wù)會(huì)對該記錄加排他鎖,所以第二個(gè)事務(wù)就一直卡住了。
OK,我們把第二個(gè)事務(wù)的執(zhí)行的SQL語句換成。
執(zhí)行結(jié)果如下,可以看到只有第二個(gè)事務(wù)回滾了。
(三)、PROPAGATION_NESTED
對于這種傳播類型,物理上只有一個(gè)事務(wù),不過可以有多個(gè)savePoint用來回滾。當(dāng)然是用這種傳播類型,需要數(shù)據(jù)庫支持savePoint,使用jdbc的也是要3.0版本以上(這個(gè)不太確定)。
執(zhí)行結(jié)果是如下,可以看到第一個(gè)事務(wù)和第三個(gè)事務(wù)提交成功了,第二個(gè)事務(wù)回滾了。物理上它們是在一個(gè)事務(wù)里的,只不過用到了保存點(diǎn)的技術(shù)。
五、其他
在寫測試代碼的時(shí)候遇到了一個(gè)關(guān)于AOP的問題,可以看到我的測試代碼,每個(gè)事務(wù)都是在一個(gè)新的class中寫的。為什么不像下面這樣寫呢?
這是因?yàn)樵赟pring的AOP中,test01調(diào)用test02, test02是不會(huì)被AOP截獲的,所以也不會(huì)被Spring進(jìn)行事務(wù)管理。原因是Spring AOP的實(shí)現(xiàn)本質(zhì)是通過動(dòng)態(tài)代理的方式去執(zhí)行真正的方法,然后在代理類里面做一些額外的事情。當(dāng)通過別的類調(diào)用MysqlTest01中的test01方法時(shí),因?yàn)槭褂昧薙pring的DI,注入的其實(shí)是一個(gè)MysqlTest01的一個(gè)代理類,而通過內(nèi)部方法調(diào)用test02時(shí),則不是。
6. Reference
Spring Framework Reference Documentation
【粉絲福利】:
《架構(gòu)師資料》領(lǐng)取方法
關(guān)注+轉(zhuǎn)發(fā),然后私信關(guān)鍵詞 【架構(gòu)】,即可獲取。
=
總結(jié)
以上是生活随笔為你收集整理的springaop事务逻辑原理_架构师:一篇文章掌握——Spring 事务管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 等待几秒_Java并发编程sy
- 下一篇: 小甲鱼python课后题答案_小甲鱼py