1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢(xún)
      選擇下列產(chǎn)品馬上在線(xiàn)溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問(wèn)題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
      如何在Spring中使用事務(wù)-創(chuàng)新互聯(lián)

      這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)如何在Spring中使用事務(wù),文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

      創(chuàng)新互聯(lián)主要從事網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)武江,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):18980820575

      1. 使用示例

      關(guān)于事務(wù)最簡(jiǎn)單的示例,就是其一致性,比如在整個(gè)事務(wù)執(zhí)行過(guò)程中,如果任何一個(gè)位置報(bào)錯(cuò)了,那么都會(huì)導(dǎo)致事務(wù)回滾,回滾之后數(shù)據(jù)的狀態(tài)將和事務(wù)執(zhí)行之前完全一致。這里我們以用戶(hù)數(shù)據(jù)為例,在插入用戶(hù)數(shù)據(jù)的時(shí)候,如果程序報(bào)錯(cuò)了,那么插入的動(dòng)作就會(huì)回滾。如下是用戶(hù)的實(shí)體:

      public class User { private long id; private String name; private int age; 
       // getter, setter...}

      如下是模擬插入用戶(hù)數(shù)據(jù)的業(yè)務(wù)代碼:

      public interface UserService { void insert(User user); 
      }@Service@Transactionalpublic class UserServiceImpl implements UserService { @Autowired 
       private JdbcTemplate jdbcTemplate; @Override 
       public void insert(User user) { 
       jdbcTemplate.update("insert into user (name, age) value (?, ?)", 
        user.getName(), user.getAge()); 
       } 
      }

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

       
        
        
        
        
        
       
       

      上述數(shù)據(jù)庫(kù)配置用戶(hù)按照各自的設(shè)置進(jìn)行配置即可。可以看到,這里對(duì)于數(shù)據(jù)庫(kù)的配置,主要包括四個(gè)方面:

      • DataSource配置:設(shè)置當(dāng)前應(yīng)用所需要連接的數(shù)據(jù)庫(kù),包括鏈接,用戶(hù)名,密碼等;

      • JdbcTemplate聲明:封裝了客戶(hù)端調(diào)用數(shù)據(jù)庫(kù)的方式,用戶(hù)可以使用其他的方式,比如JpaRepository,Mybatis等等;

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

      • tx:annotation-driven:主要用于事務(wù)驅(qū)動(dòng),其會(huì)通過(guò)AOP的方式聲明一個(gè)為事務(wù)支持的Advisor,通過(guò)該Advisor和事務(wù)的相關(guān)配置進(jìn)行事務(wù)相關(guān)操作。

      按照上述配置,我們的事務(wù)功能即配置完成,如下是我們的驅(qū)動(dòng)類(lèi)程序:

      public class TransactionApp { @Test 
       public void testTransaction() { 
       ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 
       UserService userService = ac.getBean(UserService.class); 
       User user = getUser(); 
       userService.insert(user); 
       } private User getUser() { 
       User user = new User(); 
       user.setName("Mary"); 
       user.setAge(27); return user; 
       } 
      }

      運(yùn)行上述程序之后,可以看到數(shù)據(jù)庫(kù)中成功新增了一條數(shù)據(jù)。這里如果我們將業(yè)務(wù)代碼的插入語(yǔ)句之后手動(dòng)拋出一個(gè)異常,那么,理論上插入語(yǔ)句是會(huì)回滾的。如下是修改后的service代碼:

      @Service@Transactionalpublic class UserServiceImpl implements UserService { @Autowired 
       private JdbcTemplate jdbcTemplate; @Override 
       public void insert(User user) { 
       jdbcTemplate.update("insert into user (name, age) value (?, ?)", 
        user.getName(), user.getAge()); throw new RuntimeException(); 
       } 
      }

      這里我們手動(dòng)拋出了一個(gè)RuntimeException,再次運(yùn)行上述程序之后我們發(fā)現(xiàn)數(shù)據(jù)庫(kù)中是沒(méi)有新增的數(shù)據(jù)的,這說(shuō)明我們的事務(wù)在程序出錯(cuò)后是能夠保證數(shù)據(jù)一致性的。

      2. 標(biāo)簽解析

      關(guān)于事務(wù)的實(shí)現(xiàn)原理,我們首先講解Spring是如何解析標(biāo)簽,并且封裝相關(guān)bean的,后面我們會(huì)深入講解Spring是如何封裝數(shù)據(jù)庫(kù)事務(wù)的。

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

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

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

      @Overridepublic void init() { 
       registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser()); 
       registerBeanDefinitionParser("annotation-driven", 
        new AnnotationDrivenBeanDefinitionParser()); 
       registerBeanDefinitionParser("jta-transaction-manager", 
        new JtaTransactionManagerBeanDefinitionParser()); 
      }

      可以看到,這里的annotation-driven是在AnnotationDrivenBeanDefinitionParser中進(jìn)行處理的,其parse()方法就是解析標(biāo)簽,并且注冊(cè)相關(guān)bean的方法,如下是該方法的實(shí)現(xiàn):

      public BeanDefinition parse(Element element, ParserContext parserContext) { // 注冊(cè)事務(wù)相關(guān)的監(jiān)聽(tīng)器,如果某個(gè)方法標(biāo)注了TransactionalEventListener注解, 
       // 那么該方法就是一個(gè)事務(wù)事件觸發(fā)方法,即發(fā)生某種事務(wù)事件后,將會(huì)根據(jù)該注解的設(shè)置,回調(diào)指定 
       // 類(lèi)型的方法。常見(jiàn)的事務(wù)事件有:事務(wù)執(zhí)行前和事務(wù)完成(包括報(bào)錯(cuò)后的完成)后的事件。 
       registerTransactionalEventListenerFactory(parserContext); 
       String mode = element.getAttribute("mode"); // 獲取當(dāng)前事務(wù)驅(qū)動(dòng)程序的模式,如果使用了aspectj模式,則會(huì)注冊(cè)一個(gè)AnnotationTransactionAspect 
       // 類(lèi)型的bean,用戶(hù)可以以aspectj的方式使用該bean對(duì)事務(wù)進(jìn)行更多的配置 
       if ("aspectj".equals(mode)) { 
        registerTransactionAspect(element, parserContext); 
       } else {  // 一般使用的是當(dāng)前這種方式,這種方式將會(huì)在Spring中注冊(cè)三個(gè)bean,分別是 
        // AnnotationTransactionAttributeSource,TransactionInterceptor 
        // 和BeanFactoryTransactionAttributeSourceAdvisor,并通過(guò)Aop的方式實(shí)現(xiàn)事務(wù) 
        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); 
       } return null; 
      }

      可以看到,對(duì)于事務(wù)的驅(qū)動(dòng),這里主要做了兩件事:①注冊(cè)事務(wù)相關(guān)的事件觸發(fā)器,這些觸發(fā)器由用戶(hù)自行提供,在事務(wù)進(jìn)行提交或事務(wù)完成時(shí)會(huì)觸發(fā)相應(yīng)的方法;②判斷當(dāng)前事務(wù)驅(qū)動(dòng)的模式,有默認(rèn)模式和aspectj模式,對(duì)于aspectj模式,Spring會(huì)注冊(cè)一個(gè)AnnotationTransactionAspect類(lèi)型的bean,用于用戶(hù)使用更親近于aspectj的方式進(jìn)行事務(wù)處理;對(duì)于默認(rèn)模式,這里主要是聲明了三個(gè)bean,最終通過(guò)Aop的方式進(jìn)行事務(wù)切入。下面我們看一下Spring是如何注冊(cè)這三個(gè)bean的,如下是AopAutoProxyConfigurer.configureAutoProxyCreator的源碼:

      public static void configureAutoProxyCreator(Element element, 
        ParserContext parserContext) { // 這個(gè)方法主要是在當(dāng)前BeanFactory中注冊(cè)InfrastructureAdvisorAutoProxyCreator這個(gè) 
       // bean,這個(gè)bean繼承了AbstractAdvisorAutoProxyCreator,也就是其實(shí)現(xiàn)原理與我們前面 
       // 講解的Spring Aop的實(shí)現(xiàn)原理幾乎一致 
       AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); // 這里的txAdvisorBeanName就是我們最終要注冊(cè)的bean,其類(lèi)型就是下面注冊(cè)的 
       // BeanFactoryTransactionAttributeSourceAdvisor,可以看到,其本質(zhì)是一個(gè) 
       // Advisor類(lèi)型的對(duì)象,因而Spring Aop會(huì)將其作為一個(gè)切面織入到指定的bean中 
       String txAdvisorBeanName = TransactionManagementConfigUtils 
        .TRANSACTION_ADVISOR_BEAN_NAME; // 如果當(dāng)前BeanFactory中已經(jīng)存在了目標(biāo)bean,則不進(jìn)行注冊(cè) 
       if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) { 
        Object eleSource = parserContext.extractSource(element);  // 注冊(cè)AnnotationTransactionAttributeSource,這個(gè)bean的主要作用是封裝 
        // @Transactional注解中聲明的各個(gè)屬性 
        RootBeanDefinition sourceDef = new RootBeanDefinition(  "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"); 
        sourceDef.setSource(eleSource); 
        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 
        String sourceName = parserContext.getReaderContext() 
         .registerWithGeneratedName(sourceDef);  // 注冊(cè)TransactionInterceptor類(lèi)型的bean,并且將上面的封裝屬性的bean設(shè)置為其一個(gè)屬性。 
        // 這個(gè)bean本質(zhì)上是一個(gè)Advice(可查看其繼承結(jié)構(gòu)),Spring Aop使用Advisor封裝實(shí)現(xiàn)切面 
        // 邏輯織入所需的所有屬性,但真正的切面邏輯卻是保存在其Advice屬性中的,也就是說(shuō)這里的 
        // TransactionInterceptor才是真正封裝了事務(wù)切面邏輯的bean 
        RootBeanDefinition interceptorDef = 
         new RootBeanDefinition(TransactionInterceptor.class); 
        interceptorDef.setSource(eleSource); 
        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 
        registerTransactionManager(element, interceptorDef); 
        interceptorDef.getPropertyValues().add("transactionAttributeSource", 
         new RuntimeBeanReference(sourceName)); 
        String interceptorName = parserContext.getReaderContext() 
         .registerWithGeneratedName(interceptorDef);  // 注冊(cè)BeanFactoryTransactionAttributeSourceAdvisor類(lèi)型的bean,這個(gè)bean實(shí)現(xiàn)了 
        // Advisor接口,實(shí)際上就是封裝了當(dāng)前需要織入的切面的所有所需的屬性 
        RootBeanDefinition advisorDef = 
         new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); 
        advisorDef.setSource(eleSource); 
        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 
        advisorDef.getPropertyValues().add("transactionAttributeSource", 
         new RuntimeBeanReference(sourceName)); 
        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);  if (element.hasAttribute("order")) { 
         advisorDef.getPropertyValues().add("order", element.getAttribute("order")); 
        } 
        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);  // 將需要注冊(cè)的bean封裝到CompositeComponentDefinition中,并且進(jìn)行注冊(cè) 
       
        CompositeComponentDefinition compositeDef = 
         new CompositeComponentDefinition(element.getTagName(), eleSource); 
        compositeDef.addNestedComponent(   new BeanComponentDefinition(sourceDef, sourceName)); 
        compositeDef.addNestedComponent(   new BeanComponentDefinition(interceptorDef, interceptorName)); 
        compositeDef.addNestedComponent(   new BeanComponentDefinition(advisorDef, txAdvisorBeanName)); 
        parserContext.registerComponent(compositeDef); 
       } 
      }

      如此,Spring事務(wù)相關(guān)的標(biāo)簽即解析完成,這里主要是聲明了一個(gè)BeanFactoryTransactionAttributeSourceAdvisor類(lèi)型的bean到BeanFactory中,其實(shí)際為Advisor類(lèi)型,這也是Spring事務(wù)能夠通過(guò)Aop實(shí)現(xiàn)事務(wù)的根本原因。

      3. 實(shí)現(xiàn)原理

      關(guān)于Spring事務(wù)的實(shí)現(xiàn)原理,這里需要抓住的就是,其是使用Aop實(shí)現(xiàn)的,我們知道,Aop在進(jìn)行解析的時(shí)候,最終會(huì)生成一個(gè)Adivsor對(duì)象,這個(gè)Advisor對(duì)象中封裝了切面織入所需要的所有信息,其中就包括最重要的兩個(gè)部分就是Pointcut和Adivce屬性。這里Pointcut用于判斷目標(biāo)bean是否需要織入當(dāng)前切面邏輯;Advice則封裝了需要織入的切面邏輯。如下是這三個(gè)部分的簡(jiǎn)要關(guān)系圖:

      如何在Spring中使用事務(wù)

      同樣的,對(duì)于Spring事務(wù),其既然是使用Spring Aop實(shí)現(xiàn)的,那么也同樣會(huì)有這三個(gè)成員。我們這里我們只看到了注冊(cè)的Advisor和Advice(即BeanFactoryTransactionAttributeSourceAdvisor和TransactionInterceptor),那么Pointcut在哪里呢?這里我們查看BeanFactoryTransactionAttributeSourceAdvisor的源碼可以發(fā)現(xiàn),其內(nèi)部聲明了一個(gè)TransactionAttributeSourcePointcut類(lèi)型的屬性,并且直接在內(nèi)部進(jìn)行了實(shí)現(xiàn),這就是我們需要找的Pointcut。這里這三個(gè)對(duì)象對(duì)應(yīng)的關(guān)系如下:

      如何在Spring中使用事務(wù)

      這樣,用于實(shí)現(xiàn)Spring事務(wù)的Advisor,Pointcut以及Advice都已經(jīng)找到了。關(guān)于這三個(gè)類(lèi)的具體作用,我們這里進(jìn)行整體的上的講解,后面我們將會(huì)深入其內(nèi)部講解其是如何進(jìn)行bean的過(guò)濾以及事務(wù)邏輯的織入的。

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

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

      •  TransactionInterceptor:這個(gè)bean本質(zhì)上是一個(gè)Advice,其封裝了當(dāng)前需要織入目標(biāo)bean的切面邏輯,也就是Spring事務(wù)是如果借助于數(shù)據(jù)庫(kù)事務(wù)來(lái)實(shí)現(xiàn)對(duì)目標(biāo)方法的環(huán)繞的。

      上述就是小編為大家分享的如何在Spring中使用事務(wù)了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


      分享文章:如何在Spring中使用事務(wù)-創(chuàng)新互聯(lián)
      URL鏈接:http://www.ef60e0e.cn/article/cooohp.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        温泉县| 乃东县| 柘荣县| 屯昌县| 巴林左旗| 南靖县| 遵化市| 宜兴市| 琼海市| 大竹县| 古丈县| 抚顺市| 乐陵市| 彰化市| 太湖县| 肇源县| 克拉玛依市| 隆回县| 康乐县| 丹寨县| 江津市| 闵行区| 黄龙县| 永寿县| 通化县| 镇远县| 兴国县| 桑日县| 福清市| 咸丰县| 大足县| 云霄县| 定陶县| 集安市| 若尔盖县| 嘉鱼县| 锦州市| 耿马| 普格县| 宝清县| 吉隆县|