Spring中的編程式事務(wù)和聲明式事務(wù)
spring中控制事務(wù)的方式有兩種:編程式事務(wù)和聲明式事務(wù),今天我以兩種事務(wù)出發(fā),對spring中實現(xiàn)事務(wù)的@EnableTransactionManagement和@Transaction兩個注解的底層原理進行討論。
一、編程式事務(wù)
什么是編程式事務(wù)?
硬編碼的方式實現(xiàn)事務(wù),在代碼中手動開始、提交和回滾事務(wù)
編程式事務(wù)實現(xiàn)思想是什么?
- 配置PlatformTransactionManager事務(wù)管理器去控制事務(wù)
- 配置TransactionDefinition設(shè)置事務(wù)屬性
- 配置TransactionTemplate控制事務(wù)
步驟和原理
1、定義數(shù)據(jù)源

2、定義一個PlatformTransactionManager 事務(wù)管理器,指定數(shù)據(jù)源??刂剖聞?wù)的操作(開始、提交、回滾)


3、定義TransactionDefinition 事務(wù)屬性,可以配置事務(wù)屬性信息

4、開啟事務(wù)操作。通過調(diào)用getTransaction方法



補充:ThreadLocal中存儲了datasource和connection的映射
這樣當(dāng)我們開啟事務(wù)的時候會創(chuàng)建一個數(shù)據(jù)庫連接,通過ThreadLocal保證線程的同步

5、執(zhí)行業(yè)務(wù)操作

6、commit提交/rollback回滾事務(wù)

優(yōu)缺點
優(yōu)點:
- 以在代碼中精確地控制事務(wù)的起始點、提交點和回滾點
- 實現(xiàn)更細(xì)粒度的事務(wù)管理
缺點:
- 代碼侵入性:編程式事務(wù)管理會將事務(wù)管理邏輯直接嵌入到業(yè)務(wù)代碼中,增加了代碼的復(fù)雜度和維護成本,使得業(yè)務(wù)邏輯與事務(wù)管理耦合在一起。
- 重復(fù)性工作:在多個業(yè)務(wù)方法中可能需要重復(fù)編寫事務(wù)管理邏輯,增加了代碼冗余和維護工作量。
二、聲明式事務(wù)
什么是聲明式事務(wù)?
通過配置的方式去管理事務(wù),可以是xml配置文件,也可以使用spring提供的@Transactional注解
聲明式事務(wù)實現(xiàn)思想是什么?
- 添加@EnableTransactionManagement注解
- 添加@Transactional注解
步驟和原理
1、啟用事務(wù)管理功能-配置類上加上@EnableTransactionManagement注解

2、定義事務(wù)管理器


3、需要開啟事務(wù)的目標(biāo)接口/類/方法上添加@Transaction注解


4、執(zhí)行業(yè)務(wù)邏輯

5、啟動spring容器,獲取bean執(zhí)行業(yè)務(wù)邏輯

優(yōu)缺點
優(yōu)點:
- 與業(yè)務(wù)邏輯分離:聲明式事務(wù)管理將事務(wù)管理邏輯從業(yè)務(wù)代碼中分離出來,使得業(yè)務(wù)邏輯更清晰,降低了代碼的耦合性。
- 配置簡單:通過注解或XML配置,可以簡單地定義事務(wù)的傳播行為、隔離級別等屬性,而無需在每個業(yè)務(wù)方法中編寫重復(fù)的事務(wù)管理代碼。
- 易于維護:由于事務(wù)管理邏輯集中在配置中,易于維護和修改,提高了代碼的可讀性和可維護性。
- 提高一致性:聲明式事務(wù)管理可以確保在所有業(yè)務(wù)方法中都應(yīng)用相同的事務(wù)管理策略,提高了事務(wù)管理的一致性。
缺點:
- 靈活性有限:聲明式事務(wù)管理的靈活性相對較低,無法在運行時動態(tài)地改變事務(wù)管理策略,有一定的局限性。
- RPC遠(yuǎn)程調(diào)用成功,但是本地事務(wù)回滾了,RPC調(diào)用無法回滾。并且事務(wù)中有遠(yuǎn)程調(diào)用,會拉長整個事務(wù),導(dǎo)致本地事務(wù)的數(shù)據(jù)庫連接一致被占用,最后可能會導(dǎo)致數(shù)據(jù)庫連接池耗盡

在阿里巴巴的開發(fā)手冊中也明確標(biāo)出,我們用@Transactional注解的時候要謹(jǐn)慎,大家在業(yè)務(wù)場景中要謹(jǐn)慎使用哦!

上面我已經(jīng)對spring實現(xiàn)事務(wù)的兩種方式分別進行了說明,下面我們看看它的源碼,解開事務(wù)這個神秘面紗!
三、源碼分析
@EnableTransactionManagement

作用是什么?
開啟spring自動管理事務(wù)。在spring容器啟動的時候,會攔截所有bean的創(chuàng)建,判斷當(dāng)前bean中有沒有用@Transaction注解,是不是需要讓spring管理事務(wù)
判斷規(guī)則:
- public方法上有沒有用@Transaction注解和bean的類相關(guān)的類/接口上有沒有用@Transaction注解
- 當(dāng)滿足規(guī)則之后會通過aop的方式創(chuàng)建代理,并且在代理中添加一個TransactionInterceptor攔截器
注意:@Transaction注解在代理對象被創(chuàng)建并且方法被調(diào)用時生效
@Transactional注解生效,必須確保Spring能夠為目標(biāo)類創(chuàng)建代理對象,并且方法通過代理對象調(diào)用
TransactionInterceptor攔截器的作用是什么?
攔截@Transaction方法,在方法前后添加事務(wù)額外邏輯
如果代理中還有其他攔截器,攔截器的順序如何指定呢?
通過order()方法修改事務(wù)攔截器的執(zhí)行順序
注意:默認(rèn)值是 LOWEST_PRECEDENCE = Integer.MAX_VALUE,攔截器的執(zhí)行順序是order升序
int order() default Ordered.LOWEST_PRECEDENCE;
@Import(TransactionManagementConfigurationSelector.class)在這里的作用是什么?
@Import的作用是批量導(dǎo)入需要注冊的類,完成bean的注冊
那@Import導(dǎo)入了哪些類?
通過點進去TransactionManagementConfigurationSelector我們發(fā)現(xiàn),里面有一個selectImports方法,這個方法的返回值是一個字符串?dāng)?shù)組,返回的字符串?dāng)?shù)組如果是正常的全限定類名才會被容器識別
通過查看selectImports方法源碼,我們發(fā)現(xiàn)return了兩個類-AutoProxyRegistrar、ProxyTransactionManageMentConfiguration,也就是說Import導(dǎo)入了這兩個類
- AutoProxyRegistrar:啟用spring aop功能,創(chuàng)建代理
- ProxyTransactionManageMentConfiguration:在aop中添加事務(wù)攔截器

①、AutoProxyRegistrar
點進源碼,我們看registerBeanDefinitions這個方法,看過spring容器啟動流程的小伙伴會發(fā)現(xiàn),其中流程就會調(diào)用這個方法,AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)作用是向spring容器注冊一個自動代理創(chuàng)建器,從而啟用AOP代理的功能

在方法內(nèi)部會導(dǎo)入InfrastructureAdvisorAutoProxyCreator類,給spring 容器中注冊了一個后置處理器-BeanPostProcessor,攔截所有bean的創(chuàng)建并將符合規(guī)則的bean創(chuàng)建代理,對類進行增強

在生命周期階段,創(chuàng)建bean的時候只有需要增強,就會調(diào)用BeanPostProcessor的after進行增強
②、ProxyTransactionManageMentConfiguration
配置類,一般是提供加了@Bean的一些方法。注冊了一個事務(wù)攔截器TransactionInterceptor

總結(jié)
通過對上面兩個導(dǎo)入的類的源碼分析我們明確了他們的作用,我們使用@Transaction標(biāo)注的bean會通過AutoProxyRegistrar去啟用aop功能,通過ProxyTransactionManagementConfiguration在aop中添加事務(wù)攔截器從而實現(xiàn)事務(wù)管理
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java實現(xiàn)數(shù)據(jù)結(jié)構(gòu)之并查集
并查集這種數(shù)據(jù)結(jié)構(gòu),可能出現(xiàn)的頻率不是那么高,但是還會經(jīng)常性的見到,其理解學(xué)習(xí)起來非常容易,通過本文,一定能夠輕輕松松搞定并查集2021-06-06
關(guān)于pom.xml中maven無法下載springcloud包問題
小編遇到這樣一個問題spring-cloud-starter-feign,spring-cloud-starter-eureka 一直無法下載,maven倉庫中包路徑顯示為unknown,怎么解決呢?下面小編給大家?guī)砹藀om.xml中maven無法下載springcloud包問題,需要的朋友可以參考下2022-08-08
java Socket編程實現(xiàn)I/O多路復(fù)用的示例
本文主要介紹了java Socket編程實現(xiàn)I/O多路復(fù)用的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09
SpringBoot項目使用內(nèi)置的單機任務(wù)調(diào)度功能詳解
這篇文章主要介紹了SpringBoot項目使用內(nèi)置的單機任務(wù)調(diào)度功能詳解,SpringBoot框架中提供了2個注解來讓開發(fā)者快速配置來實現(xiàn)單機定時任務(wù)調(diào)度的功能,分別是@EnableScheduling和 @Scheduled,需要的朋友可以參考下2024-01-01
關(guān)于java自定義線程池的原理與實現(xiàn)
本文介紹了如何自定義線程池和阻塞隊列,包括阻塞隊列的實現(xiàn)方法,線程池的構(gòu)建以及拒絕策略的應(yīng)用,詳細(xì)闡述了線程池中任務(wù)的提交和執(zhí)行流程,以及如何處理任務(wù)超出隊列容量的情況2022-04-04
關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別
這篇文章主要介紹了關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05

