<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring5.0源碼學(xué)習(xí)系列之事務(wù)管理概述

          共 13307字,需瀏覽 27分鐘

           ·

          2021-06-01 23:45

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  smileNicky

          來(lái)源 |  urlify.cn/FveqEf

          Spring5.0源碼學(xué)習(xí)系列之事務(wù)管理概述(十一),在學(xué)習(xí)事務(wù)管理的源碼之前,需要對(duì)事務(wù)的基本理論比較熟悉,所以本章節(jié)會(huì)對(duì)事務(wù)管理的基本理論進(jìn)行描述

          1、什么是事務(wù)?

          事務(wù)就是一組原子性的SQL操作,或者說(shuō)一個(gè)獨(dú)立的工作單元。在計(jì)算機(jī)術(shù)語(yǔ)中是指訪問(wèn)并可能更新數(shù)據(jù)庫(kù)中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元(unit)

          注意:Spring的事務(wù)支持是基于數(shù)據(jù)庫(kù)事務(wù)的,在MySQL數(shù)據(jù)庫(kù)中目前只有InnoDB或者NDB集群引擎才支持,MySQL5.0之前的默認(rèn)MyISAM存儲(chǔ)引擎是不支持事務(wù)的

          2、事務(wù)的ACID特性

          ACID其實(shí)是事務(wù)特性的英文首字母縮寫,具體含義是:原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)

          • 原子性(atomicity):事務(wù)是一個(gè)原子操作,由一系列動(dòng)作組成。整個(gè)事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾;

          • 一致性(consistency):數(shù)據(jù)庫(kù)總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另外一個(gè)一致性的狀態(tài),執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致;

          • 隔離性(isolation):因?yàn)橛卸鄠€(gè)事務(wù)處理同個(gè)數(shù)據(jù)的情況,因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開來(lái),防止數(shù)據(jù)臟讀、不可重復(fù)讀等等情況;

          • 持久性(durability):一旦事務(wù)提交,則其所做的修改就會(huì)永久保存到數(shù)據(jù)庫(kù)中。此時(shí)即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會(huì)丟;

          3、什么是臟讀、不可重復(fù)讀、幻讀?

          • 臟讀
            在A事務(wù)修改數(shù)據(jù),提交事務(wù)之前,另外一個(gè)B事務(wù)讀取了A事務(wù)未提交事務(wù)之前的數(shù)據(jù),這種情況稱之為臟讀(Dirty Read)

          • 不可重復(fù)讀
            一個(gè)A事務(wù)在讀取某些數(shù)據(jù),第1次讀取出來(lái)的數(shù)據(jù)結(jié)果和第2次讀取出來(lái)的不一致,因?yàn)樵趦纱螖?shù)據(jù)讀取期間,另外的事務(wù)對(duì)數(shù)據(jù)進(jìn)行了更改

          • 幻讀
            幻讀和不可重復(fù)讀是很類似的,不同的地方在于幻讀側(cè)重于事務(wù)對(duì)數(shù)據(jù)的刪除或者新增,都是因?yàn)樵趦纱螖?shù)據(jù)讀取期間,因?yàn)榱硗馐聞?wù)對(duì)數(shù)據(jù)的刪除還是新增,導(dǎo)致第2次讀取的數(shù)據(jù)和第1次不一致

          4、Spring事務(wù)管理核心接口


          5、事務(wù)隔離級(jí)別

          定義:事務(wù)的隔離級(jí)別定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度。隔離級(jí)別可以不同程度的解決臟讀、不可重復(fù)讀、幻讀。

          隔離級(jí)別描述臟讀不可重復(fù)讀幻讀
          ISOLATION_DEFAULT使用后端數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別,默認(rèn)的為Repeatable read (可重復(fù)讀)
          ISOLATION_READ_UNCOMMITTED不可提交讀,允許讀取尚未提交事務(wù)的數(shù)據(jù),可能會(huì)導(dǎo)致臟讀、不可重復(fù)讀、幻讀
          ISOLATION_READ_COMMITTED提交讀,讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生
          ISOLATION_REPEATABLE_READ可重復(fù)讀,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生
          ISOLATION_SERIALIZABLE串行化,這種級(jí)別是最高級(jí)別,服從ACID的隔離級(jí)別,確保阻止臟讀、不可重復(fù)讀以及幻讀

          6、事務(wù)的傳播行為

          事務(wù)傳播行為描述
          PROPAGATION_REQUIRED必須,默認(rèn)值。如果A有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將創(chuàng)建一個(gè)新的事務(wù)
          PROPAGATION_SUPPORTS支持。如果A有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行
          PROPAGATION_MANDATORY強(qiáng)制。A如果有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將拋異常
          PROPAGATION_REQUIRES_NEW必須新的。如果A有事務(wù),將A的事務(wù)掛起,B創(chuàng)建一個(gè)新的事務(wù);如果A沒(méi)有事務(wù),B創(chuàng)建一個(gè)新的事務(wù)。
          PROPAGATION_NOT_SUPPORTED不支持。如果A有事務(wù),將A的事務(wù)掛起,B將以非事務(wù)執(zhí)行;如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行。
          PROPAGATION_NEVER從不。如果A有事務(wù),B將拋異常;如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行
          PROPAGATION_NESTED嵌套。A和B底層采用保存點(diǎn)機(jī)制,形成嵌套事務(wù)。

          7、事務(wù)管理其它屬性

          前面介紹了事務(wù)管理的隔離級(jí)別和傳播行為這兩個(gè)重要的屬性,接著介紹一下事務(wù)的其它屬性

          • 事務(wù)超時(shí)屬性
            事務(wù)超時(shí),屬性值是timeout,指一個(gè)事務(wù)所允許執(zhí)行的最長(zhǎng)時(shí)間,如果超過(guò)該時(shí)間限制但事務(wù)還沒(méi)有完成,則自動(dòng)回滾事務(wù)。以 int 的值來(lái)表示超時(shí)時(shí)間,其單位是秒,默認(rèn)值為-1。

          • 事務(wù)只讀屬性
            屬性值readOnly,對(duì)于只有讀取數(shù)據(jù)查詢的事務(wù),可以指定事務(wù)類型為 readonly,即只讀事務(wù)。只讀事務(wù)不涉及數(shù)據(jù)的修改,數(shù)據(jù)庫(kù)會(huì)提供一些優(yōu)化手段,所以對(duì)于業(yè)務(wù)很明確的接口,可以適當(dāng)加上只讀屬性

          • 事務(wù)回滾規(guī)則
            屬性值rollbackFor,默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常(RuntimeException 的子類)時(shí)才會(huì)回滾,Error 也會(huì)導(dǎo)致事務(wù)回滾

          屬性名說(shuō)明
          propagation事務(wù)的傳播行為,默認(rèn)值為 REQUIRED
          isolation事務(wù)的隔離級(jí)別,默認(rèn)值采用 DEFAULT
          timeout事務(wù)的超時(shí)時(shí)間,默認(rèn)值-1,表示不會(huì)超時(shí),如果設(shè)置其它值,超過(guò)該時(shí)間限制但事務(wù)還沒(méi)有完成,則自動(dòng)回滾事務(wù)
          readOnly指定事務(wù)為只讀事務(wù),默認(rèn)值false
          rollbackFor指定能夠觸發(fā)事務(wù)回滾的異常類型,并且可以指定多個(gè)異常類型。

          8、Spring事務(wù)實(shí)現(xiàn)方式

          Spring事務(wù)代碼實(shí)現(xiàn)方式有兩種,一種是編程式事務(wù),一種是聲明式事務(wù)。所謂編程式事務(wù),是指通過(guò)Spring框架提供的TransactionTemplate或者直接使用底層的PlatformTransactionManager。聲明式事務(wù),依賴Spring AOP,配置文件中做相關(guān)的事務(wù)規(guī)則聲明或者直接使用@Transactional注解

          下面給出一個(gè)典型的轉(zhuǎn)賬匯款例子,先不用事務(wù)的方式實(shí)現(xiàn),接著使用編程式事務(wù)和聲明式事務(wù)進(jìn)行事務(wù)管理

          package com.example.springframework.dao.impl;

          import com.example.springframework.dao.AccountDao;
          import org.springframework.jdbc.core.support.JdbcDaoSupport;

          /**
           * <pre>
           *      AccountDaoImpl
           * </pre>
           *
           * <pre>
           * @author mazq
           * 修改記錄
           *    修改后版本:     修改人:  修改日期: 2021/03/25 15:51  修改內(nèi)容:
           * </pre>
           */
          public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

              @Override
              public void out(String outer, int money) {
                  super.getJdbcTemplate().update("update account set money = money - ? where usercode=?",money,outer);
              }

              @Override
              public void in(String inner, int money) {
                  super.getJdbcTemplate().update("update account set money = money + ? where usercode = ?",money , inner);
              }
          }

          package com.example.springframework.service.impl;

          import com.example.springframework.dao.AccountDao;
          import com.example.springframework.service.AccountService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.jdbc.core.support.JdbcDaoSupport;
          import org.springframework.stereotype.Service;


          /**
           * <pre>
           *      AccountServiceImpl
           * </pre>
           *
           * <pre>
           * @author mazq
           * 修改記錄
           *    修改后版本:     修改人:  修改日期: 2021/03/25 15:55  修改內(nèi)容:
           * </pre>
           */
          @Service
          public class AccountServiceImpl extends JdbcDaoSupport implements AccountService {

              AccountDao accountDao;

              public void setAccountDao(AccountDao accountDao) {
                  this.accountDao = accountDao;
              }

              public void transfer(final String outer,final String inner,final int money){
                  accountDao.out(outer , money);
                  // exception
                  // int i = 1 / 0;
                  accountDao.in(inner , money);
              }
              
          }

          代碼例子看起來(lái)是挺正常的,不過(guò)假如在accountDao.out(outer , money);, accountDao.in(inner , money);兩個(gè)事務(wù)執(zhí)行期間,發(fā)生異常,這時(shí)會(huì)怎么樣?效果如圖:Jack的賬號(hào)已經(jīng)轉(zhuǎn)賬成功,轉(zhuǎn)了1000,不過(guò)Tom并沒(méi)有收到匯款,這種情況在實(shí)際生活中肯定是不允許的,所以需要使用事務(wù)進(jìn)行管理

          9、Spring編程式事務(wù)

          Spring編程式事務(wù)實(shí)現(xiàn),通過(guò)Spring框架提供的TransactionTemplate或者直接使用底層的PlatformTransactionManager

          • 使用TransactionTemplate的方式

          private AccountDao accountDao;
          private TransactionTemplate transactionTemplate;

          public void setAccountDao(AccountDao accountDao) {
              this.accountDao = accountDao;
          }
          public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
              this.transactionTemplate = transactionTemplate;
          }

          @Override
          public void transfer(final String outer,final String inner,final int money){
              transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                  @Override
                  protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                      accountDao.out(outer , money);
                      // exception
                      int i = 1 / 0;
                      accountDao.in(inner , money);
                  }
              });
          }
          • 使用PlatformTransactionManager的方式

          private AccountDao accountDao;

          public void setAccountDao(AccountDao accountDao) {
              this.accountDao = accountDao;
          }

          @Override
          public void transferTrans(String outer, String inner, int money) {
              DataSourceTransactionManager dataSourceTransactionManager =
                      new DataSourceTransactionManager();
              // 設(shè)置數(shù)據(jù)源
              dataSourceTransactionManager.setDataSource(super.getJdbcTemplate().getDataSource());
              DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
              // 設(shè)置傳播行為屬性
              transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
              TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef);
              try {
                  accountDao.out(outer , money);
                  // exception
                  int i = 1 / 0;
                  accountDao.in(inner , money);
                  //commit
                  dataSourceTransactionManager.commit(status);
              } catch (Exception e) {
                  // rollback
                  dataSourceTransactionManager.rollback(status);
              }
          }

          10、Spring聲明式事務(wù)

          Spring聲明式事務(wù)依賴于Spring AOP,通過(guò)配置文件中做相關(guān)的事務(wù)規(guī)則聲明或者直接使用@Transactional注解

          • AOP規(guī)則聲明方式
            這種方式在 applicationContext.xml 文件中配置 aop 自動(dòng)生成代理,進(jìn)行事務(wù)管理

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
                 xmlns:aop="http://www.springframework.org/schema/aop"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

              <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
                  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
                  <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
                  <property name="username" value="root"></property>
                  <property name="password" value="minstone"></property>
              </bean>

              <bean id="accountDao" class="com.example.springframework.dao.impl.AccountDaoImpl">
                  <property name="dataSource" ref="dataSource"></property>
              </bean>

              <bean id="accountService" class="com.example.springframework.service.impl.AccountServiceImpl">
                  <property name="accountDao" ref="accountDao"></property>
                  <property name="dataSource" ref="dataSource"></property>
              </bean>
           <!-- 事務(wù)管理器配置 -->
              <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <property name="dataSource" ref="dataSource"></property>
              </bean>

              <!-- xml配置事務(wù) propagation 傳播行為isolation 隔離級(jí)別-->
              <tx:advice id="txAdvice" transaction-manager="txManager">
                  <tx:attributes>
                      <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
                  </tx:attributes>
              </tx:advice>
           
           <!-- 配置所有的Service方法都支持事務(wù)-->
              <aop:config>
               <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.springframework.service..*.*(..))"/>
           </aop:config>

            
          </beans>
          • 使用AOP注解方式
            在applicationContext.xml 配置事務(wù)管理器,將并事務(wù)管理器交予spring,在目標(biāo)類或目標(biāo)方法添加注解即可 @Transactional, proxy-target-class設(shè)置為 true :底層強(qiáng)制使用cglib 代理

          注意點(diǎn):@Transactional只能用于public方法,不管是加上類上還是方法上

          <!-- 事務(wù)管理器配置 -->
          <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <property name="dataSource" ref="dataSource"></property>
              </bean>

          <!-- 配置 Annotation 驅(qū)動(dòng),掃描@Transactional注解的類定義事務(wù)  -->
          <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>

          通過(guò)上述管理之后,一旦發(fā)生異常,兩邊都會(huì)進(jìn)行事務(wù)回滾,沒(méi)有異常,正常提交事務(wù)






          瀏覽 73
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲一级自拍 | 欧美大黑吊插老女人肛门 | 日韩亚洲精品在线观看视频 | 97豆花精品视频在线观看 | 欧美性爱视频精品 |