1. <nobr id="easjo"><address id="easjo"></address></nobr>

      <track id="easjo"><source id="easjo"></source></track>
      1. 
        

      2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
      3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>
          貴州做網站公司
          貴州做網站公司~專業!靠譜!
          10年網站模板開發經驗,熟悉國內外開源網站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等網站程序,可為您提供網站建設,網站克隆,仿站,網頁設計,網站制作,網站推廣優化等服務。我們專注高端營銷型網站,企業官網,集團官網,自適應網站,手機網站,網絡營銷,網站優化,網站服務器環境搭建以及托管運維等。為客戶提供一站式網站解決方案?。?!

          spring事務(Spring事務的用法示例與實現原理)

          來源:互聯網轉載 時間:2024-05-12 13:43:42

          關于事務,簡單來說,就是為了保證數據完整性而存在的一種工具,其主要有四大特性:原子性,一致性,隔離性和持久性。對于Spring事務,其最終還是在數據庫層面實現的,而Spring只是以一種比較優雅的方式對其進行封裝支持。本文首先會通過一個簡單的示例來講解Spring事務是如何使用的,然后會講解Spring是如何解析xml中的標簽,并對事務進行支持的。

          1. 使用示例

          關于事務最簡單的示例,就是其一致性,比如在整個事務執行過程中,如果任何一個位置報錯了,那么都會導致事務回滾,回滾之后數據的狀態將和事務執行之前完全一致。這里我們以用戶數據為例,在插入用戶數據的時候,如果程序報錯了,那么插入的動作就會回滾。如下是用戶的實體:

          publicclassUser{privatelongid;privateStringname;privateintage;//getter,setter...}

          如下是模擬插入用戶數據的業務代碼:

          publicinterfaceUserService{voidinsert(Useruser);}@Service@TransactionalpublicclassUserServiceImplimplementsUserService{@AutowiredprivateJdbcTemplatejdbcTemplate;@Overridepublicvoidinsert(Useruser){jdbcTemplate.update("insertintouser(name,age)value(?,?)",user.getName(),user.getAge());}}

          在進行事務支持時,Spring只需要使用者在需要事務支持的bean上使用@Transactional注解即可,如果需要修改事務的隔離級別和傳播特性的屬性,則使用該注解中的屬性進行指定。這里默認的隔離級別與各個數據庫一致,比如MySQL是Repeatable Read,而傳播特性默認則為Propagation.REQUIRED,即只需要當前操作具有事務即可。如下是xml文件的配置:

          <beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"><propertyname="url"value="jdbc:mysql://localhost/test?useUnicode=true"/><propertyname="driverClassName"value="com.mysql.jdbc.Driver"/><propertyname="username"value="****"/><propertyname="password"value="******"/></bean><beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><propertyname="dataSource"ref="dataSource"/></bean><beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="dataSource"/></bean><context:component-scanbase-package="com.transaction"/><tx:annotation-driven/>

          上述數據庫配置用戶按照各自的設置進行配置即可??梢钥吹?這里對于數據庫的配置,主要包括四個方面:

          • DataSource配置:設置當前應用所需要連接的數據庫,包括鏈接,用戶名,密碼等;

          • JdbcTemplate聲明:封裝了客戶端調用數據庫的方式,用戶可以使用其他的方式,比如JpaRepository,Mybatis等等;

          • TransactionManager配置:指定了事務的管理方式,這里使用的是DataSourceTransactionManager,對于不同的鏈接方式,也可以進行不同的配置,比如對于JpaRepository使用JpaTransactionManager,對于Hibernate,使用HibernateTransactionManager;

          • tx:annotation-driven:主要用于事務驅動,其會通過AOP的方式聲明一個為事務支持的Advisor,通過該Advisor和事務的相關配置進行事務相關操作。

          按照上述配置,我們的事務功能即配置完成,如下是我們的驅動類程序:

          publicclassTransactionApp{@TestpublicvoidtestTransaction(){ApplicationContextac=newClassPathXmlApplicationContext("applicationContext.xml");UserServiceuserService=ac.getBean(UserService.class);Useruser=getUser();userService.insert(user);}privateUsergetUser(){Useruser=newUser();user.setName("Mary");user.setAge(27);returnuser;}}

          運行上述程序之后,可以看到數據庫中成功新增了一條數據。這里如果我們將業務代碼的插入語句之后手動拋出一個異常,那么,理論上插入語句是會回滾的。如下是修改后的service代碼:

          @Service@TransactionalpublicclassUserServiceImplimplementsUserService{@AutowiredprivateJdbcTemplatejdbcTemplate;@Overridepublicvoidinsert(Useruser){jdbcTemplate.update("insertintouser(name,age)value(?,?)",user.getName(),user.getAge());thrownewRuntimeException();}}

          這里我們手動拋出了一個RuntimeException,再次運行上述程序之后我們發現數據庫中是沒有新增的數據的,這說明我們的事務在程序出錯后是能夠保證數據一致性的。

          2. 標簽解析

          關于事務的實現原理,我們首先講解Spring是如何解析標簽,并且封裝相關bean的,后面我們會深入講解Spring是如何封裝數據庫事務的。

          根據上面的示例,我們發現,其主要有三個部分:DataSource,TransactionManager和tx:annotation-driven標簽。這里前面兩個部分主要是聲明了兩個bean,分別用于數據庫連接的管理和事務的管理,而tx:annotation-driven才是Spring事務的驅動。根據本人前面對Spring自定義標簽的講解(Spring自定義標簽解析與實現),可以知道,這里tx:annotation-driven是一個自定義標簽,我們根據其命名空間(www.springframework.org/schema/tx)在全局范圍內搜索,可以找到其處理器指定文件spring.handlers,該文件內容如下:

          http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

          這里也就是說tx:annotation-driven標簽的解析在TxNamespaceHandler中,我們繼續打開該文件可以看到起init()方法如下:

          @Overridepublicvoidinit(){registerBeanDefinitionParser("advice",newTxAdviceBeanDefinitionParser());registerBeanDefinitionParser("annotation-driven",newAnnotationDrivenBeanDefinitionParser());registerBeanDefinitionParser("jta-transaction-manager",newJtaTransactionManagerBeanDefinitionParser());}

          可以看到,這里的annotation-driven是在AnnotationDrivenBeanDefinitionParser中進行處理的,其parse()方法就是解析標簽,并且注冊相關bean的方法,如下是該方法的實現:

          publicBeanDefinitionparse(Elementelement,ParserContextparserContext){//注冊事務相關的監聽器,如果某個方法標注了TransactionalEventListener注解,//那么該方法就是一個事務事件觸發方法,即發生某種事務事件后,將會根據該注解的設置,回調指定//類型的方法。常見的事務事件有:事務執行前和事務完成(包括報錯后的完成)后的事件。registerTransactionalEventListenerFactory(parserContext);Stringmode=element.getAttribute("mode");//獲取當前事務驅動程序的模式,如果使用了aspectj模式,則會注冊一個AnnotationTransactionAspect//類型的bean,用戶可以以aspectj的方式使用該bean對事務進行更多的配置if("aspectj".equals(mode)){registerTransactionAspect(element,parserContext);}else{//一般使用的是當前這種方式,這種方式將會在Spring中注冊三個bean,分別是//AnnotationTransactionAttributeSource,TransactionInterceptor//和BeanFactoryTransactionAttributeSourceAdvisor,并通過Aop的方式實現事務AopAutoProxyConfigurer.configureAutoProxyCreator(element,parserContext);}returnnull;}

          可以看到,對于事務的驅動,這里主要做了兩件事:①注冊事務相關的事件觸發器,這些觸發器由用戶自行提供,在事務進行提交或事務完成時會觸發相應的方法;②判斷當前事務驅動的模式,有默認模式和aspectj模式,對于aspectj模式,Spring會注冊一個AnnotationTransactionAspect類型的bean,用于用戶使用更親近于aspectj的方式進行事務處理;對于默認模式,這里主要是聲明了三個bean,最終通過Aop的方式進行事務切入。下面我們看一下Spring是如何注冊這三個bean的,如下是AopAutoProxyConfigurer.configureAutoProxyCreator的源碼:

          publicstaticvoidconfigureAutoProxyCreator(Elementelement,ParserContextparserContext){//這個方法主要是在當前BeanFactory中注冊InfrastructureAdvisorAutoProxyCreator這個//bean,這個bean繼承了AbstractAdvisorAutoProxyCreator,也就是其實現原理與我們前面//講解的SpringAop的實現原理幾乎一致AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext,element);//這里的txAdvisorBeanName就是我們最終要注冊的bean,其類型就是下面注冊的//BeanFactoryTransactionAttributeSourceAdvisor,可以看到,其本質是一個//Advisor類型的對象,因而SpringAop會將其作為一個切面織入到指定的bean中StringtxAdvisorBeanName=TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;//如果當前BeanFactory中已經存在了目標bean,則不進行注冊if(!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)){ObjecteleSource=parserContext.extractSource(element);//注冊AnnotationTransactionAttributeSource,這個bean的主要作用是封裝//@Transactional注解中聲明的各個屬性RootBeanDefinitionsourceDef=newRootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");sourceDef.setSource(eleSource);sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);StringsourceName=parserContext.getReaderContext().registerWithGeneratedName(sourceDef);//注冊TransactionInterceptor類型的bean,并且將上面的封裝屬性的bean設置為其一個屬性。//這個bean本質上是一個Advice(可查看其繼承結構),SpringAop使用Advisor封裝實現切面//邏輯織入所需的所有屬性,但真正的切面邏輯卻是保存在其Advice屬性中的,也就是說這里的//TransactionInterceptor才是真正封裝了事務切面邏輯的beanRootBeanDefinitioninterceptorDef=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);//注冊BeanFactoryTransactionAttributeSourceAdvisor類型的bean,這個bean實現了//Advisor接口,實際上就是封裝了當前需要織入的切面的所有所需的屬性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"));}parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName,advisorDef);//將需要注冊的bean封裝到CompositeComponentDefinition中,并且進行注冊CompositeComponentDefinitioncompositeDef=newCompositeComponentDefinition(element.getTagName(),eleSource);compositeDef.addNestedComponent(newBeanComponentDefinition(sourceDef,sourceName));compositeDef.addNestedComponent(newBeanComponentDefinition(interceptorDef,interceptorName));compositeDef.addNestedComponent(newBeanComponentDefinition(advisorDef,txAdvisorBeanName));parserContext.registerComponent(compositeDef);}}

          如此,Spring事務相關的標簽即解析完成,這里主要是聲明了一個BeanFactoryTransactionAttributeSourceAdvisor類型的bean到BeanFactory中,其實際為Advisor類型,這也是Spring事務能夠通過Aop實現事務的根本原因。

          3. 實現原理

          關于Spring事務的實現原理,這里需要抓住的就是,其是使用Aop實現的,我們知道,Aop在進行解析的時候,最終會生成一個Apsor對象,這個Advisor對象中封裝了切面織入所需要的所有信息,其中就包括最重要的兩個部分就是Pointcut和Apce屬性。這里Pointcut用于判斷目標bean是否需要織入當前切面邏輯;Advice則封裝了需要織入的切面邏輯。如下是這三個部分的簡要關系圖:

          同樣的,對于Spring事務,其既然是使用Spring Aop實現的,那么也同樣會有這三個成員。我們這里我們只看到了注冊的Advisor和Advice(即BeanFactoryTransactionAttributeSourceAdvisor和TransactionInterceptor),那么Pointcut在哪里呢?這里我們查看BeanFactoryTransactionAttributeSourceAdvisor的源碼可以發現,其內部聲明了一個TransactionAttributeSourcePointcut類型的屬性,并且直接在內部進行了實現,這就是我們需要找的Pointcut。這里這三個對象對應的關系如下:

          這樣,用于實現Spring事務的Advisor,Pointcut以及Advice都已經找到了。關于這三個類的具體作用,我們這里進行整體的上的講解,后面我們將會深入其內部講解其是如何進行bean的過濾以及事務邏輯的織入的。

          • BeanFactoryTransactionAttributeSourceAdvisor:封裝了實現事務所需的所有屬性,包括Pointcut,Advice,TransactionManager以及一些其他的在Transactional注解中聲明的屬性;

          • TransactionAttributeSourcePointcut:用于判斷哪些bean需要織入當前的事務邏輯。這里可想而知,其判斷的基本邏輯就是判斷其方法或類聲明上有沒有使用@Transactional注解,如果使用了就是需要織入事務邏輯的bean;

          • TransactionInterceptor:這個bean本質上是一個Advice,其封裝了當前需要織入目標bean的切面邏輯,也就是Spring事務是如果借助于數據庫事務來實現對目標方法的環繞的。

          4. 小結

          本文首先通過一個簡單的例子講解了Spring事務是如何使用的,然后講解了Spring事務進行標簽解析的時候做了哪些工作,***講解了Spring事務是如何與Spring Aop進行一一對應的,并且是如何通過Spring Aop實現將事務邏輯織入目標bean的。

          到此,相信大家對“Spring事務的用法示例與實現原理”有了更深的了解,不妨來實際操作一番吧!這里是本站網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

          標簽:spring事務-

          c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...

          2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...

          :喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...

          定期存款是死期嗎?定期存款指的就是死期存款。銀行存款的類型可以分為定期存款和活期存款這兩大類型,死期只民間對于定期的一種通俗說法,用戶可以根據自己的需要選擇存款類型,通常短期存款可以選擇活期,取款手續比較簡單,長期存款則可以選擇定期。定期存款也可以稱為定期存單。銀行和存款人,在辦理存款之前會事先對存款期限、利率等要素進行約定,到期后存款人可以對本金和利息進行支取的操作。如果在到期之前,存款人向銀行...

          家族信托有什么潛在的風險第一項風險在于設立端,缺乏專業的頂層規劃設計。很多人認為家族信托是一個產品,關心的其收益率問題。其實,家族信托與理財產品相去甚遠。 家族信托主要是為了實現家族財富的風險隔離與跨代傳承,短期的收益不是也不應當成為其核心目標。要想讓家族信托跨越委托人的生命周期,長久地守護住財產,首先要確保這個家族信托的合法有效性,并能夠提前預見未來極端事件并做出安排。第二項風險在于運營端,受托...

          平安行銷支持管理系統是什么?其實就是一個簡單的網上信息查詢的系統,不過很多打中國平安集團的業務員,并不是特別的熟悉,如果你想要擁有更加方便的工作的話,那么就需要登錄到該系統了,在我們登錄系統的時候可以使用自己的平安行銷支持管理系統的賬號和密碼登錄,這個地方需要告訴大家的是,平安行銷支持管理系統,只有業務員才有賬號和密碼,其他人是不能夠登錄的。中國平安保險e行銷何時啟動經營?1、中國平安保險e行銷已...

          TOP
          国产初高中生视频在线观看|亚洲一区中文|久久亚洲欧美国产精品|黄色网站入口免费进人
          1. <nobr id="easjo"><address id="easjo"></address></nobr>

              <track id="easjo"><source id="easjo"></source></track>
              1. 
                

              2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
              3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>