Spring 事務(wù)底層原理
@EnableTransactionManagement工作原理 Spring事務(wù)基本執(zhí)行原理 Spring事務(wù)詳細執(zhí)行流程 Spring事務(wù)傳播機制 Spring事務(wù)傳播機制分類 案例分析 情況1 情況2 情況3 情況4 Spring事務(wù)強制回滾 TransactionSynchronization

一、@EnableTransactionManagement工作原理

開啟Spring事務(wù)本質(zhì)上就是增加了一個Advisor,但我們使用@EnableTransactionManagement注解來開啟Spring事務(wù)是,該注解代理的功能就是向Spring容器中添加了兩個Bean:
AutoProxyRegistrar ProxyTransactionManagementConfiguration
AutoProxyRegistrar主要的作用是向Spring容器中注冊了一個InfrastructureAdvisorAutoProxyCreator的Bean。而InfrastructureAdvisorAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator,所以這個類的主要作用就是開啟自動代理的作用,也就是一個BeanPostProcessor,會在初始化后步驟中去尋找Advisor類型的Bean,并判斷當(dāng)前某個Bean是否有匹配的Advisor,是否需要利用動態(tài)代理產(chǎn)生一個代理對象。
ProxyTransactionManagementConfiguration是一個配置類,它又定義了另外三個bean:
BeanFactoryTransactionAttributeSourceAdvisor:一個Advisor AnnotationTransactionAttributeSource:相當(dāng)于 BeanFactoryTransactionAttributeSourceAdvisor中的PointcutTransactionInterceptor:相當(dāng)于 BeanFactoryTransactionAttributeSourceAdvisor中的Advice
AnnotationTransactionAttributeSource就是用來判斷某個類上是否存在@Transactional注解,或者判斷某個方法上是否存在@Transactional注解的。
TransactionInterceptor就是代理邏輯,當(dāng)某個類中存在@Transactional注解時,到時就產(chǎn)生一個代理對象作為Bean,代理對象在執(zhí)行某個方法時,最終就會進入到TransactionInterceptor的invoke()方法。

二、Spring事務(wù)基本執(zhí)行原理

一個Bean在執(zhí)行Bean的創(chuàng)建生命周期時,會經(jīng)過InfrastructureAdvisorAutoProxyCreator的初始化后的方法,會判斷當(dāng)前Bean對象是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配邏輯為判斷該Bean的類上是否存在@Transactional注解,或者類中的某個方法上是否存在@Transactional注解,如果存在則表示該Bean需要進行動態(tài)代理產(chǎn)生一個代理對象作為Bean對象。
該代理對象在執(zhí)行某個方法時,會再次判斷當(dāng)前執(zhí)行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配則執(zhí)行該Advisor中的TransactionInterceptor的invoke()方法,執(zhí)行基本流程為:
利用所配置的PlatformTransactionManager事務(wù)管理器新建一個數(shù)據(jù)庫連接 修改數(shù)據(jù)庫連接的autocommit為false 執(zhí)行MethodInvocation.proceed()方法,簡單理解就是執(zhí)行業(yè)務(wù)方法,其中就會執(zhí)行sql 如果沒有拋異常,則提交 如果拋了異常,則回滾
三、Spring事務(wù)詳細執(zhí)行流程
Spring事務(wù)執(zhí)行流程圖:https://www.processon.com/view/link/5fab6edf1e0853569633cc06


四、Spring事務(wù)傳播機制

a()和b()方法中的所有sql需要在同一個事務(wù)中嗎? a()和b()方法需要單獨的事務(wù)嗎? a()需要在事務(wù)中執(zhí)行,b()還需要在事務(wù)中執(zhí)行嗎? 等等情況…
首先,代理對象執(zhí)行 a()方法前,先利用事務(wù)管理器新建一個數(shù)據(jù)庫連接a將數(shù)據(jù)庫連接a的autocommit改為false 把數(shù)據(jù)庫連接a設(shè)置到ThreadLocal中 執(zhí)行 a()方法中的sql執(zhí)行 a()方法過程中,調(diào)用了b()方法(注意用代理對象調(diào)用b()方法)代理對象執(zhí)行 b()方法前,判斷出來了當(dāng)前線程中已經(jīng)存在一個數(shù)據(jù)庫連接a了,表示當(dāng)前線程其實已經(jīng)擁有一個Spring事務(wù)了,則進行掛起掛起就是把ThreadLocal中的數(shù)據(jù)庫連接a從ThreadLocal中移除,并放入一個掛起資源對象中 掛起完成后,再次利用事務(wù)管理器新建一個數(shù)據(jù)庫連接b 將數(shù)據(jù)庫連接b的autocommit改為false 把數(shù)據(jù)庫連接b設(shè)置到ThreadLocal中 執(zhí)行 b()方法中的sqlb()方法正常執(zhí)行完,則從ThreadLocal中拿到數(shù)據(jù)庫連接b進行提交提交之后會恢復(fù)所掛起的數(shù)據(jù)庫連接a,這里的恢復(fù),其實只是把在掛起資源對象中所保存的數(shù)據(jù)庫連接a再次設(shè)置到ThreadLocal中 a()方法正常執(zhí)行完,則從ThreadLocal中拿到數(shù)據(jù)庫連接a進行提交
五、Spring事務(wù)傳播機制分類
案例分析
情況1
public class UserService {private UserService userService;public void test() {// test方法中的sqluserService.a();}public void a() {// a方法中的sql}}
新建一個數(shù)據(jù)庫連接conn 設(shè)置conn的autocommit為false 執(zhí)行test方法中的sql 執(zhí)行a方法中的sql 執(zhí)行conn的commit()方法進行提交
假如是這種情況:
public class UserService {private UserService userService;public void test() {// test方法中的sqluserService.a();int result = 100/0;}public void a() {// a方法中的sql}}
所以上面這種情況的執(zhí)行流程如下:
新建一個數(shù)據(jù)庫連接conn 設(shè)置conn的autocommit為false 執(zhí)行test方法中的sql 執(zhí)行a方法中的sql 拋出異常 執(zhí)行conn的rollback()方法進行回滾,所以兩個方法中的sql都會回滾掉
情況3
假如是這種情況:
public class UserService {private UserService userService;public void test() {// test方法中的sqluserService.a();}public void a() {// a方法中的sqlint result = 100/0;}}
新建一個數(shù)據(jù)庫連接conn 設(shè)置conn的autocommit為false 執(zhí)行test方法中的sql 執(zhí)行a方法中的sql 拋出異常 執(zhí)行conn的rollback()方法進行回滾,所以兩個方法中的sql都會回滾掉
情況4
如果是這種情況:
public class UserService {private UserService userService;public void test() {// test方法中的sqluserService.a();}(propagation = Propagation.REQUIRES_NEW)public void a() {// a方法中的sqlint result = 100/0;}}
所以上面這種情況的執(zhí)行流程如下:
新建一個數(shù)據(jù)庫連接conn 設(shè)置conn的autocommit為false 執(zhí)行test方法中的sql 又新建一個數(shù)據(jù)庫連接conn2 執(zhí)行a方法中的sql 拋出異常 執(zhí)行conn2的rollback()方法進行回滾 繼續(xù)拋異常,對于test()方法而言,它會接收到一個異常,然后拋出 執(zhí)行conn的rollback()方法進行回滾,最終還是兩個方法中的sql都回滾了
六、Spring事務(wù)強制回滾
a()調(diào)用b()方法時,如果b()方法拋了異常,但是在a()方法捕獲了,那么a()的事務(wù)還是會正常提交的,但是有的時候,我們捕獲異常可能僅僅只是不把異常信息返回給客戶端,而是為了返回一些更友好的錯誤信息,而這個時候,我們還是希望事務(wù)能回滾的,那這個時候就得告訴Spring把當(dāng)前事務(wù)回滾掉,做法就是:public void test(){// 執(zhí)行sqltry {b();} catch (Exception e) {// 構(gòu)造友好的錯誤信息返回TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}}public void b() throws Exception {throw new Exception();}

七、TransactionSynchronization

public class UserService {private JdbcTemplate jdbcTemplate;private UserService userService;public void test(){TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {public void suspend() {System.out.println("test被掛起了");}public void resume() {System.out.println("test被恢復(fù)了");}public void beforeCommit(boolean readOnly) {System.out.println("test準(zhǔn)備要提交了");}public void beforeCompletion() {System.out.println("test準(zhǔn)備要提交或回滾了");}public void afterCommit() {System.out.println("test提交成功了");}public void afterCompletion(int status) {System.out.println("test提交或回滾成功了");}});jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");System.out.println("test");userService.a();}(propagation = Propagation.REQUIRES_NEW)public void a(){TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {public void suspend() {System.out.println("a被掛起了");}public void resume() {System.out.println("a被恢復(fù)了");}public void beforeCommit(boolean readOnly) {System.out.println("a準(zhǔn)備要提交了");}public void beforeCompletion() {System.out.println("a準(zhǔn)備要提交或回滾了");}public void afterCommit() {System.out.println("a提交成功了");}public void afterCompletion(int status) {System.out.println("a提交或回滾成功了");}});jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");System.out.println("a");}}
推薦閱讀:
不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)
企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案
論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?
企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!
