版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析目錄一、基于xml形式開啟Transaction1.創(chuàng)建數(shù)據(jù)庫user2.創(chuàng)建一個maven項(xiàng)目3.通過xml形式配置事務(wù)1)創(chuàng)建Spring命名空間2)開啟事務(wù)配置3)創(chuàng)建UserService類4.測試事務(wù)1)拋出RuntimeException2)注釋掉RuntimeException二、事務(wù)開啟入口TxNamespaceHandlerAnnotationDrivenBeanDefinitionParser三、AOP驅(qū)動事務(wù)TransactionInterceptor創(chuàng)建事務(wù)回滾事務(wù)
一、基于xml形式開啟Transaction
1.創(chuàng)建數(shù)據(jù)庫user
/*
NavicatPremiumDataTransfer
SourceServer:win-local
SourceServerType:MySQL
SourceServerVersion:50737
SourceHost:localhost:3306
SourceSchema:db0
TargetServerType:MySQL
TargetServerVersion:50737
FileEncoding:65001
Date:24/04/202520:27:41
SETNAMESutf8mb4;
SETFOREIGN_KEY_CHECKS=0;
------------------------------
--Tablestructureforuser
------------------------------
DROPTABLEIFEXISTS`user`;
CREATETABLE`user`(
`id`bigint(20)NOTNULLAUTO_INCREMENT,
`name`varchar(255)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNULLDEFAULTNULL,
`age`int(11)NULLDEFAULTNULL,
PRIMARYKEY(`id`)USINGBTREE
)ENGINE=InnoDBAUTO_INCREMENT=1CHARACTERSET=utf8mb4COLLATE=utf8mb4_general_ciROW_FORMAT=Dynamic;
SETFOREIGN_KEY_CHECKS=1;
2.創(chuàng)建一個maven項(xiàng)目
不用Springboot依賴,引入mysql驅(qū)動依賴、spring-beans、spring-jdbc、Spring-context依賴
dependencies
dependency
groupIdmysql/groupId
artifactIdmysql-connector-java/artifactId
version5.1.46/version
/dependency
dependency
groupIdorg.springframework/groupId
artifactIdspring-beans/artifactId
version5.3.18/version
/dependency
!--springjdbc依賴spring-tx--
dependency
groupIdorg.springframework/groupId
artifactIdspring-jdbc/artifactId
version5.3.18/version
/dependency
dependency
groupIdmons/groupId
artifactIdcommons-dbcp2/artifactId
version2.7.0/version
/dependency
dependency
groupIdorg.springframework/groupId
artifactIdspring-context/artifactId
version5.3.18/version
/dependency
dependency
groupIdjunit/groupId
artifactIdjunit/artifactId
version4.13.2/version
/dependency
/dependencies
3.通過xml形式配置事務(wù)
1)創(chuàng)建Spring命名空間
首先在resources目錄下創(chuàng)建一個spring.xml文件,Spring框架為了聲明自己的Xml規(guī)范,在beans標(biāo)簽里定義了spring框架指定模塊的協(xié)議配置,我們可以通過Indexof/schema訪問spring框架的所有模塊包,各模塊包含了不同版本的xsd文件。
點(diǎn)擊進(jìn)入context目錄,查看xsd文件:
比如我要通過xml的形式配置一個bean,需要在beans標(biāo)簽中聲明xmln的值為:
/schema/beans
如果我想用spring的context模塊,那么需要聲明
xmlns:context=/schema/context
同時在xsi:schemeLocation里添加context的url和spring-contxt.xsd的url:
/schema/context
/schema/context/spring-context.xsd
例如我創(chuàng)建一個能在xml中使用spring-beans模塊,spring-txt模塊,spring-context模塊的配置如下:
xmlversion="1.0"encoding="UTF-8"
beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:context="/schema/context"
xmlns:tx="/schema/tx"
xsi:schemaLocation="
/schema/beans/schema/beans/spring-beans.xsd
/schema/context/schema/context/spring-context.xsd
/schema/tx/schema/tx/spring-tx.xsd
/beans
如果沒有在beans標(biāo)簽里聲明協(xié)議,那么在配置bean時會出現(xiàn)找不到指定標(biāo)簽的問題。
2)開啟事務(wù)配置
在spring.xml文件中添加配置事務(wù)配置,使用annotation-driven屬性開啟事務(wù)啟動,
tx:annotation-driventransaction-manager="transactionManager"proxy-target-mode="proxy"/
proxy-target-class默認(rèn)為false,mode默認(rèn)模式為proxy,可不用配置,待會從源碼角度分析不同模式的事務(wù)開啟。
接著配置transactionManager,指定>
tx:annotation-driventransaction-manager="transactionManager"proxy-target-mode="proxy"/
beanid="transactionManager"
propertyname="dataSource"ref="ds"/
/bean
DataSourceTransactionManager里包含了DataSource屬性配置:
因此我們需要接著配置數(shù)據(jù)源bean別名為
beanid="ds"destroy-method="close"
propertyname="driverClassName"value="com.mysql.jdbc.Driver"/
propertyname="username"value="root"/
propertyname="password"value="root"/
propertyname="url"value="jdbc:mysql://localhost:3306/db0useSSL=false"/
propertyname="initialSize"value="5"/
propertyname="maxIdle"value="2"/
propertyname="maxTotal"value="100"/
/bean
接著給Service配置一個bean,引用dataSource數(shù)據(jù)源。
!--配置bean,指定數(shù)據(jù)源--
beanid="userService"
propertyname="dataSource"ref="ds"/
/bean
3)創(chuàng)建UserService類
通過dataSoucebean注入JDBCTemplate,添加一個update(intid,Stringname)方法,類上添加@Transactional(propagation=Propagation.REQUIRED)。
packageservice;
importorg.springframework.jdbc.core.JdbcTemplate;
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;
importjavax.sql.DataSource;
@Transactional(propagation=Propagation.REQUIRED)
publicclassUserService{
privateJdbcTemplatejdbcTemplate;
publicvoidsetDataSource(DataSourcedataSource){
this.jdbcTemplate=newJdbcTemplate(dataSource);
publicStringgetUserName(intid){
returnjdbcTemplate.query("select*fromdb0.userwhereid=",rs-rs.next()rs.getString(2):"",newObject[]{id});
publicvoidupdateUser(intid,Stringname){
jdbcTemplate.update("updateusersetname=whereid=",newObject[]{name,id});
//thrownewRuntimeException("error!");
}
4.測試事務(wù)
使用ClassPathXmlApplicationContext類加載spring.xml文件
importorg.junit.Test;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
importservice.UserService;
publicclassUserServiceTests{
@Test
publicvoidtestTransaction(){
ApplicationContextcontext=newClassPathXmlApplicationContext("spring.xml");
UserServiceuserService=context.getBean("userService",UserService.class);
Stringname=userService.getUserName(1);
System.out.println("名字:"+name);
userService.updateUser(1,"bing");
StringupdateName=userService.getUserName(1);
System.out.println("更新后的名字:"+updateName);
}
數(shù)據(jù)庫一條記錄:
1)拋出RuntimeException
update方法里放開//thrownewRuntimeException(error!注釋,執(zhí)行后
數(shù)據(jù)庫里的記錄沒有修改,@Tranasctional注解生效。
2)注釋掉RuntimeException
重新執(zhí)行后,觀察結(jié)果
數(shù)據(jù)庫也更新過來了。
前面的篇幅從xml的配置形式解釋了Transaction集成過程,為什么要從xml形式入手transaction,是為了后面閱讀Spring-tx源碼做準(zhǔn)備。
二、事務(wù)開啟入口TxNamespaceHandler
根據(jù)spring.xml文件里配置的tx:annitation-driven關(guān)鍵字在Spring框架里全局搜索,找到目標(biāo)類TxNamespaceHandler。位于spring-tx模塊中的org.springframework.transaction.config包下。
/*
*Copyright2002-2012theoriginalauthororauthors.
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*/licenses/LICENSE-2.0
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
packageorg.springframework.transaction.config;
importorg.w3c.dom.Element;
importorg.springframework.beans.factory.xml.NamespaceHandlerSupport;
*{@codeNamespaceHandler}allowingfortheconfigurationof
*declarativetransactionmanagementusingeitherXMLorusingannotations.
*pThisnamespacehandleristhecentralpieceoffunctionalityinthe
*Springtransactionmanagementfacilitiesandofferstwoapproaches
*todeclarativelymanagetransactions.
*pOneapproachusestransactionsemanticsdefinedinXMLusingthe
*{@codetx:advice}elements,theotherusesannotations
*incombinationwiththe{@codetx:annotation-driven}element.
*BothapproachedaredetailedtogreatextentintheSpringreferencemanual.
*@authorRobHarrop
*@authorJuergenHoeller
*@since2.0
publicclassTxNamespaceHandlerextendsNamespaceHandlerSupport{
staticfinalStringTRANSACTION_MANAGER_ATTRIBUTE="transaction-manager";
staticfinalStringDEFAULT_TRANSACTION_MANAGER_BEAN_NAME="transactionManager";
staticStringgetTransactionManagerName(Elementelement){
return(element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE)
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE):DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
@Override
publicvoidinit(){
registerBeanDefinitionParser("advice",newTxAdviceBeanDefinitionParser());
//注冊事務(wù)
registerBeanDefinitionParser("annotation-driven",newAnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager",newJtaTransactionManagerBeanDefinitionParser());
}
找到了annotation-driven,這個地方創(chuàng)建了一個AnnotationDrivenBeanDefinitionParser實(shí)例。
AnnotationDrivenBeanDefinitionParser
AnnotationDrivenBeanDefinitionParser類的作用是解析spring.xml里的配置tx:annotation-driven標(biāo)簽,并根據(jù)配置的mode選擇不同的模式取創(chuàng)建Transaction的整個初始化流程,此處也就是整個架Transaction架構(gòu)的開始地方。
Spring事務(wù)注冊的模式為動態(tài)代理模式,具體實(shí)現(xiàn)有2種:aspectj和proxy,可通過配置來選擇使用那種形式的事務(wù)注冊,如果不配置mode那么使用默認(rèn)的proxy形式創(chuàng)建,如果我們要使用aspectj模式開啟事務(wù),那么就配置mode=aspectj。
tx:annotation-driventransaction-manager="transactionManager"mode="aspectj"
我們可以看到Spring事務(wù)的開啟是默認(rèn)是以AOP為基礎(chǔ)的。
三、AOP驅(qū)動事務(wù)
AopAutoProxyConfigurer的configureAutoProxyCreator方法注冊了3個Bean,該3個Bean是驅(qū)動Spring事務(wù)架構(gòu)的核心支柱,分別是TransactionAttributeSource、TransactionInterceptor、TransactionAttributeSourceAdvisor。
privatestaticclassAopAutoProxyConfigurer{
publicstaticvoidconfigureAutoProxyCreator(Elementelement,ParserContextparserContext){
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext,element);
StringtxAdvisorBeanName=TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if(!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)){
ObjecteleSource=parserContext.extractSource(element);
//CreatetheTransactionAttributeSourcedefinition.
RootBeanDefinitionsourceDef=newRootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
StringsourceName=parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
//CreatetheTransactionInterceptordefinition.
RootBeanDefinitioninterceptorDef=newRootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element,interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource",newRuntimeBeanReference(sourceName));
StringinterceptorName=parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
//CreatetheTransactionAttributeSourceAdvisordefinition.
RootBeanDefinitionadvisorDef=newRootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource",newRuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName",interceptorName);
if(element.hasAttribute("order")){
advisorDef.getPropertyValues().add("order",element.getAttribute("order"));
//事務(wù)通知器transactionadvisor,基于AOP實(shí)現(xiàn)的advisor
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName,advisorDef);
CompositeComponentDefinitioncompositeDef=newCompositeComponentDefinition(element.getTagName(),eleSource);
compositeDef.addNestedComponent(newBeanComponentDefinition(sourceDef,sourceName));
compositeDef.addNestedComponent(newBeanComponentDefinition(interceptorDef,interceptorName));
compositeDef.addNestedComponent(newBeanComponentDefinition(advisorDef,txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
其中TransactionInterceptor是Spring事務(wù)的目標(biāo)方法的增強(qiáng),通過代理完成Spring事務(wù)的提交、異常處理和回滾。
TransactionInterceptor
TransactionInterceptor是Spring事務(wù)對目標(biāo)方法的增強(qiáng)器,說簡單點(diǎn)就是一層代理,基于Aop實(shí)現(xiàn),實(shí)現(xiàn)了spring-aop的Advice接口,同時實(shí)現(xiàn)了IntializingBean和BeanFactoryAware接口,只要有事務(wù)的執(zhí)行,那么目標(biāo)方法的調(diào)用類在invoke()方法會生成一個代理對象,通過invoke()方法對目標(biāo)調(diào)用方法進(jìn)行增強(qiáng)。
@FunctionalInterface
publicinterfaceMethodInterceptorextendsInterceptor{
*Implementthismethodtoperformextratreatmentsbeforeand
*aftertheinvocation.Politeimplementationswouldcertainly
*liketoinvoke{@linkJoinpoint#proceed()}.
*@paraminvocationthemethodinvocationjoinpoint
*@returntheresultofthecallto{@linkJoinpoint#proceed()};
*mightbeinterceptedbytheinterceptor
*@throwsThrowableiftheinterceptorsorthetargetobject
*throwsanexception
Objectinvoke(MethodInvocationinvocation)throwsThrowable;
}
TransactionInterceptor的invoke()實(shí)現(xiàn):
@Override
@Nullable
publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{
//Workoutthetargetclass:maybe{@codenull}.
//TheTransactionAttributeSourceshouldbepassedthetargetclass
//aswellasthemethod,whichmaybefromaninterface.
ClasstargetClass=(invocation.getThis()!=nullAopUtils.getTargetClass(invocation.getThis())
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 硬化地面鋪設(shè)施工作業(yè)方案
- GB/T 36132-2025綠色工廠評價通則
- 2026渤海銀行總行交易銀行部國際業(yè)務(wù)中心招聘考試參考題庫及答案解析
- 2026年甘肅蘭州永登縣婦幼保健院招聘考試參考試題及答案解析
- 2026年蕪湖市西灣中學(xué)招聘頂崗教師1名考試備考試題及答案解析
- 2026年甘肅隴南成縣招聘城鎮(zhèn)公益性崗位人員42人考試備考試題及答案解析
- 2026重慶市銅梁區(qū)巴川街道福利院工作人員招聘2人考試備考試題及答案解析
- 2026云南迪慶州兵役登記考試參考題庫及答案解析
- 2025湖北鄂州市鄂城區(qū)國控投資集團(tuán)下屬子公司招聘部分崗位條件調(diào)整及延長考試參考試題及答案解析
- 2026四川外派至中鐵建昆侖高速公路運(yùn)營管理有限公司四川指揮部運(yùn)行監(jiān)測調(diào)度中心監(jiān)控員德遂高速收費(fèi)員招聘3人考試備考題庫及答案解析
- 自來水公司招聘考試筆試題目
- GB/T 325.2-2010包裝容器鋼桶第2部分:最小總?cè)萘?08L、210L和216.5L全開口鋼桶
- GB/T 24526-2009炭素材料全硫含量測定方法
- GB/T 17793-2010加工銅及銅合金板帶材外形尺寸及允許偏差
- GB/T 15107-2005旅游鞋
- 單晶結(jié)構(gòu)分析原理與實(shí)踐
- 蒸汽管道安裝監(jiān)理實(shí)施細(xì)則
- 2023年成都東部集團(tuán)有限公司招聘筆試模擬試題及答案解析
- 2022年武漢首義科技創(chuàng)新投資發(fā)展集團(tuán)有限公司招聘筆試試題及答案解析
- 2022更新國家開放大學(xué)電大《計算機(jī)應(yīng)用基礎(chǔ)(本)》終結(jié)性考試試題答案任務(wù)一
- 《計算機(jī)導(dǎo)論》課程教學(xué)大綱(本科)
評論
0/150
提交評論