Spring中事務(wù)的使用、抽象機(jī)制及模擬Spring事務(wù)實(shí)現(xiàn)
本文大綱如下:

編程式事務(wù)
Spring提供了兩種編程式事務(wù)管理的方法
使用
TransactionTemplate或者TransactionalOperator.直接實(shí)現(xiàn)
TransactionManager接口
如果是使用的是命令式編程,Spring推薦使用TransactionTemplate 來(lái)完成編程式事務(wù)管理,如果是響應(yīng)式編程,那么使用TransactionalOperator更加合適。
TransactionTemplate
使用示例(我這里直接用的官網(wǎng)提供的例子了)
public?class?SimpleService?implements?Service?{
????private?final?TransactionTemplate?transactionTemplate;
?
????//?使用構(gòu)造對(duì)transactionTemplate進(jìn)行初始化
????//?需要提供一個(gè)transactionManager
????public?SimpleService(PlatformTransactionManager?transactionManager)?{
????????this.transactionTemplate?=?new?TransactionTemplate(transactionManager);
????}
????public?Object?someServiceMethod()?{
????????return?transactionTemplate.execute(new?TransactionCallback()?{
????????????public?Object?doInTransaction(TransactionStatus?status)?{
????????????????//?這里實(shí)現(xiàn)自己的相關(guān)業(yè)務(wù)邏輯
????????????????updateOperation1();
????????????????return?resultOfUpdateOperation2();
????????????}
????????});
????}
}
在上面的例子中,我們顯示的使用了TransactionTemplate來(lái)完成事務(wù)管理,通過(guò)實(shí)現(xiàn)TransactionCallback接口并在其doInTransaction方法中完成了我們對(duì)業(yè)務(wù)的處理。我們可以大概看下TransactionTemplate的execute方法的實(shí)現(xiàn):
?public? ?T?execute(TransactionCallback ?action) ?throws?TransactionException?{
??Assert.state(this.transactionManager?!=?null,?"No?PlatformTransactionManager?set");
??if?(this.transactionManager?instanceof?CallbackPreferringPlatformTransactionManager)?{
???return?((CallbackPreferringPlatformTransactionManager)?this.transactionManager).execute(this,?action);
??}
??else?{
????????????//?1.通過(guò)事務(wù)管理器開(kāi)啟事務(wù)
???TransactionStatus?status?=?this.transactionManager.getTransaction(this);
???T?result;
???try?{
????????????????//?2.執(zhí)行傳入的業(yè)務(wù)邏輯
????result?=?action.doInTransaction(status);
???}
???catch?(RuntimeException?|?Error?ex)?{
????//?3.出現(xiàn)異常,進(jìn)行回滾
????rollbackOnException(status,?ex);
????throw?ex;
???}
???catch?(Throwable?ex)?{
????//?3.出現(xiàn)異常,進(jìn)行回滾
????rollbackOnException(status,?ex);
????throw?new?UndeclaredThrowableException(ex,?"TransactionCallback?threw?undeclared?checked?exception");
???}
????????????//?4.正常執(zhí)行完成的話,提交事務(wù)
???this.transactionManager.commit(status);
???return?result;
??}
?}
這些方法具體的實(shí)現(xiàn)我們暫且不看,后續(xù)進(jìn)行源碼分析時(shí)都會(huì)詳細(xì)介紹,之所以將這個(gè)代碼貼出來(lái)是讓大家更好的理解TransactionTemplate的工作機(jī)制:實(shí)際上就是通過(guò)一個(gè)TransactionCallback封裝了業(yè)務(wù)邏輯,然后TransactionTemplate會(huì)在事務(wù)的上下文中調(diào)用。
在上面的例子中doInTransaction是有返回值的,而實(shí)際上有時(shí)候并不需要返回值,這種情況下,我們可以使用TransactionCallbackWithoutResult提代TransactionCallback。
transactionTemplate.execute(new?TransactionCallbackWithoutResult()?{
????protected?void?doInTransactionWithoutResult(TransactionStatus?status)?{
????????updateOperation1();
????????updateOperation2();
????}
});
?實(shí)際上我們還可以通過(guò)TransactionTemplate指定事務(wù)的屬性,例如隔離級(jí)別、超時(shí)時(shí)間、傳播行為等等
TransactionTemplate是線程安全的,我們可以全局配置一個(gè)TransactionTemplate,然后所有的類都共享這個(gè)TransactionTemplate。但是,如果某個(gè)類需要特殊的事務(wù)配置,例如需要定制隔離級(jí)別,那么我們就有必要去創(chuàng)建不同的TransactionTemplate。
?
TransactionOperator
?TransactionOperator適用于響應(yīng)式編程的情況,這里就不做詳細(xì)介紹了
?
TransactionManager
實(shí)際上TransactionTemplate內(nèi)部也是使用TransactionManager來(lái)完成事務(wù)管理的,我們之前也看過(guò)它的execute方法的實(shí)現(xiàn)了,其實(shí)內(nèi)部就是調(diào)用了TransactionManager的方法,實(shí)際上就是分為這么幾步
開(kāi)啟事務(wù)
執(zhí)行業(yè)務(wù)邏輯
出現(xiàn)異常進(jìn)行回滾
正常執(zhí)行則提交事務(wù)
這里我還是直接用官網(wǎng)給出的例子
//?定義事務(wù)
DefaultTransactionDefinition?def?=?new?DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//?txManager,事務(wù)管理器
//?通過(guò)事務(wù)管理器開(kāi)啟一個(gè)事務(wù)
TransactionStatus?status?=?txManager.getTransaction(def);
try?{
????//?完成自己的業(yè)務(wù)邏輯
}
catch?(MyException?ex)?{
????//?出現(xiàn)異常,進(jìn)行回滾
????txManager.rollback(status);
????throw?ex;
}
//?正常執(zhí)行完成,提交事務(wù)
txManager.commit(status);
我們?cè)诤筮叺脑创a分析中其實(shí)重點(diǎn)分析的也就是TransactionManager的源碼。
申明式事務(wù)
在對(duì)編程式事務(wù)有一定了解之后我們會(huì)發(fā)現(xiàn),編程式事務(wù)存在下面幾個(gè)問(wèn)題:
「我們的業(yè)務(wù)代碼跟事務(wù)管理的代碼混雜在一起」。
「每個(gè)需要事務(wù)管理的地方都需要寫重復(fù)的代碼」
如何解決呢?這就要用到申明式事務(wù)了,實(shí)現(xiàn)申明式事務(wù)一般有兩種方式
基于XML配置
基于注解
申明式事務(wù)事務(wù)的實(shí)現(xiàn)原理如下(圖片來(lái)源于官網(wǎng)):

「實(shí)際上就是結(jié)合了APO自動(dòng)代理跟事務(wù)相關(guān)API」。通過(guò)開(kāi)啟AOP自動(dòng)代理并向容器中注冊(cè)了事務(wù)需要的通知(Transaction Advisor),在Transaction Advisor調(diào)用了事務(wù)相關(guān)API,其實(shí)內(nèi)部也是調(diào)用了TransactionManager的方法。
基于XML配置這種方式就不講了,筆者近兩年時(shí)間沒(méi)用過(guò)XML配置,我們主要就看看通過(guò)注解方式來(lái)實(shí)現(xiàn)申明式事務(wù)。主要涉及到兩個(gè)核心注解
@EnableTransactionManagement@Transactional
@EnableTransactionManagement這個(gè)注解主要有兩個(gè)作用,其一是,開(kāi)啟AOP自動(dòng)代理,其二是,添加事務(wù)需要用到的通知(Transaction Advisor),如果你對(duì)AOP有一定了解的話那你應(yīng)該知道一個(gè)Advisor實(shí)際上就是一個(gè)綁定了切點(diǎn)(Pointcut)的通知(Advice),通過(guò)@EnableTransactionManagement這個(gè)注解導(dǎo)入的Advisor所綁定的切點(diǎn)就是通過(guò)@Transactional來(lái)定義的。
申明式事務(wù)的例子我這里就省去了,我相信沒(méi)幾個(gè)人不會(huì)用吧.....
Spring對(duì)事務(wù)的抽象
Spring事務(wù)抽象的關(guān)鍵就是事務(wù)策略的概念,事務(wù)策略是通過(guò)TransactionManager接口定義的。TransactionManager本身只是一個(gè)標(biāo)記接口,它有兩個(gè)直接子接口
ReactiveTransactionManager,這個(gè)接口主要用于在響應(yīng)式編程模型下,不是我們要討論的重點(diǎn)PlatformTransactionManager,命令式編程模型下我們使用這個(gè)接口。
?關(guān)于響應(yīng)式跟命令式編程都可以單獨(dú)寫一篇文章了,本文重點(diǎn)不是討論這兩種編程模型,可以認(rèn)為平常我們使用的都是命令式編程
?
PlatformTransactionManager
PlatformTransactionManager接口定義
public?interface?PlatformTransactionManager?extends?TransactionManager?{
?//?開(kāi)啟事務(wù)
????TransactionStatus?getTransaction(TransactionDefinition?definition)?throws?TransactionException;
?
????//?提交事務(wù)
????void?commit(TransactionStatus?status)?throws?TransactionException;
?
????//?回滾事務(wù)
????void?rollback(TransactionStatus?status)?throws?TransactionException;
}
PlatformTransactionManager是命令式編程模型下Spring事務(wù)機(jī)制的中心接口,定義了完成一個(gè)事務(wù)必須的三個(gè)步驟,也就是說(shuō)定義了事務(wù)實(shí)現(xiàn)的規(guī)范
開(kāi)啟事務(wù)
提交事務(wù)
回滾事務(wù)
通常來(lái)說(shuō),我們不會(huì)直接實(shí)現(xiàn)這個(gè)接口,而是通過(guò)繼承AbstractPlatformTransactionManager,這個(gè)類是一個(gè)抽象類,主要用作事務(wù)管理的模板,這個(gè)抽象類已經(jīng)實(shí)現(xiàn)了事務(wù)的傳播行為以及跟事務(wù)相關(guān)的同步管理。
回頭看接口中定義的三個(gè)方法,首先是開(kāi)啟事務(wù)的方法,從方法簽名上來(lái)看,其作用就是通過(guò)一個(gè)TransactionDefinition來(lái)獲取一個(gè)TransactionStatus類型的對(duì)象。為了更好的理解Spring中事務(wù)的抽象我們有必要了解下這兩個(gè)接口
TransactionDefinition
接口定義如下:
public?interface?TransactionDefinition?{
?
????//?定義了7中事務(wù)的傳播機(jī)制
?int?PROPAGATION_REQUIRED?=?0;
?int?PROPAGATION_SUPPORTS?=?1;
?int?PROPAGATION_MANDATORY?=?2;
?int?PROPAGATION_REQUIRES_NEW?=?3;
?int?PROPAGATION_NOT_SUPPORTED?=?4;
?int?PROPAGATION_NEVER?=?5;
?int?PROPAGATION_NESTED?=?6;
????//?4種隔離級(jí)別,-1代表的是使用數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別
????//?比如在MySQL下,使用的就是ISOLATION_REPEATABLE_READ(可重復(fù)讀)
?int?ISOLATION_DEFAULT?=?-1;
?int?ISOLATION_READ_UNCOMMITTED?=?1;??
?int?ISOLATION_READ_COMMITTED?=?2;?
?int?ISOLATION_REPEATABLE_READ?=?4;?
?int?ISOLATION_SERIALIZABLE?=?8;??
????
????//?事務(wù)的超時(shí)時(shí)間,默認(rèn)不限制時(shí)間
?int?TIMEOUT_DEFAULT?=?-1;
?
????//?提供了對(duì)上面三個(gè)屬性的get方法
?default?int?getPropagationBehavior()?{
??return?PROPAGATION_REQUIRED;
?}
?default?int?getIsolationLevel()?{
??return?ISOLATION_DEFAULT;
?}
?default?int?getTimeout()?{
??return?TIMEOUT_DEFAULT;
?}
?
????//?事務(wù)是否是只讀的,默認(rèn)不是
?default?boolean?isReadOnly()?{
??return?false;
?}
????
????//?事務(wù)的名稱
?@Nullable
?default?String?getName()?{
??return?null;
?}
????
????//?返回一個(gè)只讀的TransactionDefinition
????//?只對(duì)屬性提供了getter方法,所有屬性都是接口中定義的默認(rèn)值
?static?TransactionDefinition?withDefaults()?{
??return?StaticTransactionDefinition.INSTANCE;
?}
}
從這個(gè)接口的名字上我們也能知道,它的主要完成了對(duì)事務(wù)定義的抽象,這些定義有些是數(shù)據(jù)庫(kù)層面本身就有的,例如隔離級(jí)別、是否只讀、超時(shí)時(shí)間、名稱。也有些是Spring賦予的,例如事務(wù)的傳播機(jī)制。Spring中一共定義了7種事務(wù)的傳播機(jī)制
TransactionDefinition.PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(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)前沒(méi)有事務(wù),則拋出異常。
TransactionDefinition.PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED。
關(guān)于事務(wù)的傳播在源碼分析的文章中我會(huì)重點(diǎn)介紹,現(xiàn)在大家留個(gè)印象即可。
我們?cè)谑褂蒙昝魇绞聞?wù)的時(shí)候,會(huì)通過(guò)@Transactional這個(gè)注解去申明某個(gè)方法需要進(jìn)行事務(wù)管理,在@Transactional中可以定義事務(wù)的屬性,這些屬性實(shí)際上就會(huì)被封裝到一個(gè)TransactionDefinition中,當(dāng)然封裝的時(shí)候肯定不是直接使用的接口,而是這個(gè)接口的一個(gè)實(shí)現(xiàn)類RuleBasedTransactionAttribute。RuleBasedTransactionAttribute,該類的繼承關(guān)系如下:

DefaultTransactionDefinition,實(shí)現(xiàn)了TransactionDefinition,并為其中的定義的屬性提供了默認(rèn)值//?默認(rèn)的傳播機(jī)制為required,沒(méi)有事務(wù)新建一個(gè)事務(wù)
//?有事務(wù)的話加入當(dāng)前事務(wù)
private?int?propagationBehavior?=?PROPAGATION_REQUIRED;
//?隔離級(jí)別跟數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別一直
private?int?isolationLevel?=?ISOLATION_DEFAULT;
//?默認(rèn)為-1,不設(shè)置超時(shí)時(shí)間
private?int?timeout?=?TIMEOUT_DEFAULT;
//?默認(rèn)不是只讀的
private?boolean?readOnly?=?false;TransactionAttribute,擴(kuò)展了``DefaultTransactionDefinition`,新增了兩個(gè)事務(wù)的屬性//?用于指定事務(wù)使用的事務(wù)管理器的名稱
String?getQualifier();
//?指定在出現(xiàn)哪種異常時(shí)才進(jìn)行回滾
boolean?rollbackOn(Throwable?ex);DefaultTransactionAttribute,繼承了DefaultTransactionDefinition,同時(shí)實(shí)現(xiàn)了TransactionAttribute接口,定義了默認(rèn)的回滾異常//?拋出RuntimeException/Error才進(jìn)行回滾
public?boolean?rollbackOn(Throwable?ex)?{
????return?(ex?instanceof?RuntimeException?||?ex?instanceof?Error);
}RuleBasedTransactionAttribute,@Transactional注解的rollbackFor等屬性就會(huì)被封裝到這個(gè)類中,允許程序員自己定義回滾的異常,如果沒(méi)有指定回滾的異常,默認(rèn)「拋出RuntimeException/Error才進(jìn)行回滾」
TransactionStatus

TransactionExecution,這個(gè)接口也是用于描述事務(wù)的狀態(tài),TransactionStatus是在其上做的擴(kuò)展,內(nèi)部定義了以下幾個(gè)方法//?判斷當(dāng)前事務(wù)是否是一個(gè)新的事務(wù)
//?不是一個(gè)新事務(wù)的話,那么需要加入到已經(jīng)存在的事務(wù)中
boolean?isNewTransaction();
//?事務(wù)是否被標(biāo)記成RollbackOnly
//?如果被標(biāo)記成了RollbackOnly,意味著事務(wù)只能被回滾
void?setRollbackOnly();?
boolean?isRollbackOnly();
//?是否事務(wù)完成,回滾或提交都意味著事務(wù)完成了
boolean?isCompleted();SavepointManager,定義了管理保存點(diǎn)(Savepoint)的方法,隔離級(jí)別為NESTED時(shí)就是通過(guò)設(shè)置回滾點(diǎn)來(lái)實(shí)現(xiàn)的,內(nèi)部定義了這么幾個(gè)方法//?創(chuàng)建保存點(diǎn)
Object?createSavepoint()?throws?TransactionException;
//?回滾到指定保存點(diǎn)
void?rollbackToSavepoint(Object?savepoint)?throws?TransactionException;
//?移除回滾點(diǎn)
void?releaseSavepoint(Object?savepoint)?throws?TransactionException;TransactionStatus,繼承了上面這些接口,額外提供了兩個(gè)方法//用于判斷當(dāng)前事務(wù)是否設(shè)置了保存點(diǎn)
boolean?hasSavepoint();
//?這個(gè)方法復(fù)寫了父接口Flushable中的方法
//?主要用于刷新會(huì)話
//?對(duì)于Hibernate/jpa而言就是調(diào)用了其session/entityManager的flush方法
void?flush();
TransactionDefinition的主要作用是給出一份事務(wù)屬性的定義,然后事務(wù)管理器根據(jù)給出的定義來(lái)創(chuàng)建事務(wù),TransactionStatus主要是用來(lái)描述創(chuàng)建后的事務(wù)的狀態(tài)TransactionDefinition跟TransactionStatus有一定了解后,我們?cè)倩氐?/span>PlatformTransactionManager接口本身,PlatformTransactionManager作為事務(wù)管理器的基礎(chǔ)接口只是定義管理一個(gè)事務(wù)必須的三個(gè)方法:開(kāi)啟事務(wù),提交事務(wù),回滾事務(wù),接口僅僅是定義了規(guī)范而已,真正做事的還是要依賴它的實(shí)現(xiàn)類,所以我們來(lái)看看它的繼承關(guān)系PlatformTransactionManager的實(shí)現(xiàn)類

AbstractPlatformTransactionManager,Spring提供的一個(gè)事務(wù)管理的基類,提供了事務(wù)管理的模板,實(shí)現(xiàn)了Spring事務(wù)管理的一個(gè)標(biāo)準(zhǔn)流程判斷當(dāng)前是否已經(jīng)存在一個(gè)事務(wù) 應(yīng)用合適的事務(wù)傳播行為 在必要的時(shí)候掛起/恢復(fù)事務(wù) 提交時(shí)檢查事務(wù)是否被標(biāo)記成為 rollback-only在回滾時(shí)做適當(dāng)?shù)男薷模ㄊ菆?zhí)行真實(shí)的回滾/還是將事務(wù)標(biāo)記成 rollback-only)觸發(fā)注冊(cè)的同步回調(diào) 在 AbstractPlatformTransactionManager提供了四個(gè)常見(jiàn)的子類,其說(shuō)明如下
Spring中事務(wù)的同步機(jī)制
資源的同步 行為的同步
SQL(如果是單條的SQL實(shí)際上沒(méi)有必要開(kāi)啟事務(wù)),為了保證事務(wù)所有的SQL都能夠使用一個(gè)數(shù)據(jù)庫(kù)連接,這個(gè)時(shí)候我們需要將數(shù)據(jù)庫(kù)連接跟事務(wù)進(jìn)行同步,這個(gè)時(shí)候數(shù)據(jù)庫(kù)連接就是跟這個(gè)事務(wù)同步的一個(gè)資源。TransactionSynchronizationManager,這是一個(gè)抽象類,其中所有的方法都是靜態(tài)的,并且所有的方法都是圍繞它所申明的幾個(gè)靜態(tài)常量字段,如下://?這就是同步的資源,Spring就是使用這個(gè)完成了連接的同步
private?static?final?ThreadLocal
ThreadLocal實(shí)現(xiàn)的,對(duì)于ThreadLocal本文不做詳細(xì)分析,如果對(duì)ThreadLocal還不了解的同學(xué)也沒(méi)有關(guān)系,對(duì)于本文而言你只需要知道ThreadLocal能將資源跟當(dāng)前線程綁定即可,例如ThreadLocal這個(gè)屬性就代表要將一個(gè)map綁定到當(dāng)前線程,它提供了set跟get方法,分別用于將屬性綁定到線程上以及獲取線程上綁定的屬性。synchronizations之外其余的應(yīng)該都很好理解,synchronizations中綁定的是一個(gè)TransactionSynchronization的集合,那么這個(gè)TransactionSynchronization有什么用呢?我們來(lái)看看它的接口定義public?interface?TransactionSynchronization?extends?Flushable?{
?//?事務(wù)完成的狀態(tài)
????//?0?提交
????//?1?回滾
????//?2?異常狀態(tài),例如在事務(wù)執(zhí)行時(shí)出現(xiàn)異常,然后回滾,回滾時(shí)又出現(xiàn)異常
????//?就會(huì)被標(biāo)記成狀態(tài)2
?int?STATUS_COMMITTED?=?0;
?int?STATUS_ROLLED_BACK?=?1;
?int?STATUS_UNKNOWN?=?2;
????//?我們綁定的這些TransactionSynchronization需要跟事務(wù)同步
????//?1.如果事務(wù)掛起,我們需要將其掛起
????//?2.如果事務(wù)恢復(fù),我們需要將其恢復(fù)
?default?void?suspend()?{
?}
?default?void?resume()?{
?}
?@Override
?default?void?flush()?{
?}
?
????//?在事務(wù)執(zhí)行過(guò)程中,提供的一些回調(diào)方法
?default?void?beforeCommit(boolean?readOnly)?{
?}
?default?void?beforeCompletion()?{
?}
?default?void?afterCommit()?{
?}
?default?void?afterCompletion(int?status)?{
?}
}
行為的同步。模擬Spring事務(wù)的實(shí)現(xiàn)
jdbc,在模擬之前我們先明確兩點(diǎn)切點(diǎn)應(yīng)該如何定義? 通知要實(shí)現(xiàn)什么功能?
JDBC相關(guān)依賴即可,該項(xiàng)目?jī)H僅是一個(gè)Spring環(huán)境下的Java項(xiàng)目,沒(méi)有Web依賴,也不是SpringBoot項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下:
<project?xmlns="http://maven.apache.org/POM/4.0.0"
?????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
?????????xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd">
????<modelVersion>4.0.0modelVersion>
????<groupId>com.dmz.frameworkgroupId>
????<artifactId>mybatisartifactId>
????<version>1.0-SNAPSHOTversion>
????<dependencies>
????????
????????<dependency>
????????????<groupId>mysqlgroupId>
????????????<artifactId>mysql-connector-javaartifactId>
????????????<version>8.0.15version>
????????dependency>
????????
????????<dependency>
????????????<groupId>org.springframeworkgroupId>
????????????<artifactId>spring-contextartifactId>
????????????<version>5.2.6.RELEASEversion>
????????dependency>
????????
????????<dependency>
????????????<groupId>org.springframeworkgroupId>
????????????<artifactId>spring-aopartifactId>
????????????<version>5.2.6.RELEASEversion>
????????dependency>
????????<dependency>
????????????<groupId>org.aspectjgroupId>
????????????<artifactId>aspectjweaverartifactId>
????????????<version>1.9.5version>
????????dependency>
????dependencies>
project>
//?開(kāi)啟AOP跟掃描組件即可
@EnableAspectJAutoProxy
@ComponentScan("com.dmz.mybatis.tx_demo")
public?class?Config?{
}
public?class?TransactionUtil?{
????public?static?final?ThreadLocal?synchronousConnection?= ;?i++)?{
????????????new?ThreadLocal();
????private?TransactionUtil()?{
????}
????public?static?Connection?startTransaction()?{
????????Connection?connection?=?synchronousConnection.get();
????????if?(connection?==?null)?{
????????????try?{
????????????????//?這里替換成你自己的連接地址即可
????????????????connection?=?DriverManager
????????????????????????.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8",?"root",?"123");
????????????????synchronousConnection.set(connection);
????????????????connection.setAutoCommit(false);
????????????}?catch?(SQLException?e)?{
????????????????e.printStackTrace();
????????????}
????????}
????????return?connection;
????}
????public?static?int?execute(String?sql,?Object...?args)?{
????????Connection?connection?=?startTransaction();
????????try?(PreparedStatement?preparedStatement?=?connection.prepareStatement(sql))?{
????????????if?(args?!=?null)?{
????????????????for?(int?i?=?1;?i?1
????????????????????preparedStatement.setObject(i,?args[i?-?1]);
????????????????}
????????????}
????????????return?preparedStatement.executeUpdate();
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????????return?0;
????}
????public?static?void?commit()?{
????????try?(Connection?connection?=?synchronousConnection.get())?{
????????????connection.commit();
????????????synchronousConnection.remove();
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}
????public?static?void?rollback()?{
????????try?(Connection?connection?=?synchronousConnection.get())?{
????????????connection.rollback();
????????????synchronousConnection.remove();
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}
}
@Component
public?class?UserService?{
????public?void?saveUser()?{
????????TransactionUtil.execute
????????????????("INSERT?INTO?`test`.`user`(`id`,?`name`)?VALUES?(?,??)",?100,?"dmz");
????????//?測(cè)試回滾
????????//?throw?new?RuntimeException();
????}
}
@Component
@Aspect
public?class?TxAspect?{
????@Pointcut("execution(public?*?com.dmz.mybatis.tx_demo.service..*.*(..))")
????private?void?pointcut()?{
????}
????@Around("pointcut()")
????public?Object?around(JoinPoint?joinPoint)?throws?Throwable?{
????????//?在方法執(zhí)行前開(kāi)啟事務(wù)
????????TransactionUtil.startTransaction();
????????//?執(zhí)行業(yè)務(wù)邏輯
????????Object?proceed?=?null;
????????try?{
????????????ProceedingJoinPoint?method?=?(ProceedingJoinPoint)?joinPoint;
????????????proceed?=?method.proceed();
????????}?catch?(Throwable?throwable)?{
????????????//?出現(xiàn)異常進(jìn)行回滾
????????????TransactionUtil.rollback();
????????????return?proceed;
????????}
????????//?方法執(zhí)行完成后提交事務(wù)
????????TransactionUtil.commit();
????????return?proceed;
????}
}
public?class?Main?{
????public?static?void?main(String[]?args)?{
????????AnnotationConfigApplicationContext?ac?=
????????????????new?AnnotationConfigApplicationContext(Config.class);
????????UserService?userService?=?ac.getBean(UserService.class);
????????userService.saveUser();
????}
}
總結(jié)
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
