<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>

          一文搞懂什么是事務(wù)

          共 7856字,需瀏覽 16分鐘

           ·

          2020-12-20 15:52

          一文搞懂什么是事務(wù)


          • 一文搞懂什么是事務(wù)

            • 事務(wù)概念

            • 臟讀、不可重復(fù)讀、幻讀

            • 數(shù)據(jù)庫事務(wù)的隔離級別

            • Spring事務(wù)傳播行為

            • Spring 事務(wù)的兩種實現(xiàn)

            • 使用事務(wù)時需要注意的點

            • 總結(jié)


          事務(wù)概念

          我們要理解下事務(wù)概念:什么是事務(wù)呢?事務(wù)是并發(fā)控制的單位,是用戶定義的一個操作序列。有四個特性(ACID):

          • 原子性(Atomicity):事務(wù)是數(shù)據(jù)庫的邏輯工作單位,事務(wù)中包括的諸操作要么全做,要么全不做。

          • 一致性(Consistency):事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。一致性與原子性是密切相關(guān)的。

          • 隔離性(Isolation):一個事務(wù)的執(zhí)行不能被其他事務(wù)干擾。

          • 持續(xù)性/永久性(Durability):一個事務(wù)一旦提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就應(yīng)該是永久性的。

          以上是書面解釋,簡單來說就是把你的操作統(tǒng)一化,要么所有操作都成功,要么就都不成功,如果執(zhí)行中有某一項操作失敗,其之前所有的操作都回滾到未執(zhí)行這一系列操作之前的狀態(tài)。

          臟讀、不可重復(fù)讀、幻讀

          先理解這三種由于并發(fā)訪問導(dǎo)致的數(shù)據(jù)讀取問題,再理解事務(wù)隔離級別就簡單多了。

          臟讀

          A事務(wù)讀取B事務(wù)尚未提交的數(shù)據(jù),此時如果B事務(wù)發(fā)生錯誤并執(zhí)行回滾操作,那么A事務(wù)讀取到的數(shù)據(jù)就是臟數(shù)據(jù)。就好像原本的數(shù)據(jù)比較干凈、純粹,此時由于B事務(wù)更改了它,這個數(shù)據(jù)變得不再純粹。這個時候A事務(wù)立即讀取了這個臟數(shù)據(jù),但事務(wù)B良心發(fā)現(xiàn),又用回滾把數(shù)據(jù)恢復(fù)成原來干凈、純粹的樣子,而事務(wù)A卻什么都不知道,最終結(jié)果就是事務(wù)A讀取了此次的臟數(shù)據(jù),稱為臟讀。

          這種情況常發(fā)生于轉(zhuǎn)賬與取款操作中

          不可重復(fù)讀(前后多次讀取,數(shù)據(jù)內(nèi)容不一致)

          事務(wù)A在執(zhí)行讀取操作,由整個事務(wù)A比較大,前后讀取同一條數(shù)據(jù)需要經(jīng)歷很長的時間 。而在事務(wù)A第一次讀取數(shù)據(jù),比如此時讀取了小明的年齡為20歲,事務(wù)B執(zhí)行更改操作,將小明的年齡更改為30歲,此時事務(wù)A第二次讀取到小明的年齡時,發(fā)現(xiàn)其年齡是30歲,和之前的數(shù)據(jù)不一樣了,也就是數(shù)據(jù)不重復(fù)了,系統(tǒng)不可以讀取到重復(fù)的數(shù)據(jù),成為不可重復(fù)讀。

          幻讀(前后多次讀取,數(shù)據(jù)總量不一致)

          事務(wù)A在執(zhí)行讀取操作,需要兩次統(tǒng)計數(shù)據(jù)的總量,前一次查詢數(shù)據(jù)總量后,此時事務(wù)B執(zhí)行了新增數(shù)據(jù)的操作并提交后,這個時候事務(wù)A讀取的數(shù)據(jù)總量和之前統(tǒng)計的不一樣,就像產(chǎn)生了幻覺一樣,平白無故的多了幾條數(shù)據(jù),成為幻讀。

          小總結(jié):不可重復(fù)讀和幻讀到底有什么區(qū)別?

          (1) 不可重復(fù)讀是讀取了其他事務(wù)更改的數(shù)據(jù),針對update操作

          解決:使用行級鎖,鎖定該行,事務(wù)A多次讀取操作完成后才釋放該鎖,這個時候才允許其他事務(wù)更改剛才的數(shù)據(jù)。

          (2) 幻讀是讀取了其他事務(wù)新增的數(shù)據(jù),針對insert和delete操作

          解決:使用表級鎖,鎖定整張表,事務(wù)A多次讀取數(shù)據(jù)總量之后才釋放該鎖,這個時候才允許其他事務(wù)新增數(shù)據(jù)。

          ?

          這時候再理解事務(wù)隔離級別就簡單多了呢。

          ?

          數(shù)據(jù)庫事務(wù)的隔離級別

          SQL 標(biāo)準(zhǔn)定義的四種隔離級別被 ANSI(美國國家標(biāo)準(zhǔn)學(xué)會)和 ISO/IEC(國際標(biāo)準(zhǔn))采用,每種級別對事務(wù)的處理能力會有不同程度的影響。事務(wù)是一系列的動作,它們綜合在一起才是一個完整的工作單元,這些動作必須全部完成,如果有一個失敗的話,那么事務(wù)就會回滾到最開始的狀態(tài),仿佛什么都沒發(fā)生過一樣。

          數(shù)據(jù)庫事務(wù)的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個級別可以逐個解決臟讀 、不可重復(fù)讀 、幻讀 這幾類問題。

          DEFAULT

          默認值,表示使用底層數(shù)據(jù)庫的默認隔離級別。大部分數(shù)據(jù)庫為READ_COMMITTED(MySql默認REPEATABLE_READ)

          READ UNCOMMITTED(讀未提交)

          該隔離級別表示一個事務(wù)可以讀取另一個事務(wù)修改但還沒有提交的數(shù)據(jù)。該級別不能防止臟讀和不可重復(fù)讀,因此很少使用該隔離級別。

          READ_COMMITTED (讀提交)

          該隔離級別表示一個事務(wù)只能讀取另一個事務(wù)已經(jīng)提交的數(shù)據(jù)。該級別可以防止臟讀,這也是大多數(shù)情況下的推薦值。

          REPEATABLE_READ (可重復(fù)讀)

          該隔離級別表示一個事務(wù)在整個過程中可以多次重復(fù)執(zhí)行某個查詢,并且每次返回的記錄都相同。即使在多次查詢之間有新增的數(shù)據(jù)滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復(fù)讀。

          SERIALIZABLE (串行化)

          所有的事務(wù)依次逐個執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。在該隔離級別下事務(wù)都是串行順序執(zhí)行的,MySQL 數(shù)據(jù)庫的 InnoDB 引擎會給讀操作隱式加一把讀共享鎖,從而避免了臟讀、不可重讀復(fù)讀和幻讀問題。

          MVCC(多版本并發(fā)控制)

          mysql中,默認的事務(wù)隔離級別是可重復(fù)讀(repeatable-read),為了解決不可重復(fù)讀,innodb采用了MVCC(多版本并發(fā)控制)來解決這一問題。MVCC是利用在每條數(shù)據(jù)后面加了隱藏的兩列(創(chuàng)建版本號和刪除版本號),每個事務(wù)在開始的時候都會有一個遞增的版本號,用來和查詢到的每行記錄的版本號進行比較。?MYSQL MVCC

          Spring事務(wù)傳播行為

          先來介紹下Spring事務(wù)傳播行為的使用方法:

          @Transactional(propagation=Propagation.REQUIRED)
          public?void?test()?{
          ????????//todo?something
          }
          ?

          注解@Transactional 通過使用 propagation 屬性設(shè)置,例如:@Transactional(propagation = Propagation.REQUIRED)

          ?

          它的propagation屬性取值有以下幾種:

          public?enum?Propagation?{

          ????REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

          ????SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

          ????MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

          ????REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

          ????NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

          ????NEVER(TransactionDefinition.PROPAGATION_NEVER),

          ????NESTED(TransactionDefinition.PROPAGATION_NESTED);

          }

          事務(wù)傳播行為:

          • REQUIRED :如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個新的事務(wù)。
          • SUPPORTS :如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運行。
          • MANDATORY :如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。
          • REQUIRES_NEW :創(chuàng)建一個新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
          • NOT_SUPPORTED :以非事務(wù)方式運行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
          • NEVER :以非事務(wù)方式運行,如果當(dāng)前存在事務(wù),則拋出異常。
          • NESTED :如果當(dāng)前存在事務(wù),則創(chuàng)建一個事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運行;如果當(dāng)前沒有事務(wù),則該取值等價于 REQUIRED

          Spring 事務(wù)的兩種實現(xiàn)

          Spring 支持“編程式事務(wù)”管理和“聲明式事務(wù)”管理兩種方式:

          1編程式事務(wù):編程式事務(wù)使用 TransactionTemplate 或者直接使用底層的 PlatformTransactionManager 實現(xiàn)事務(wù)。對于編程式事務(wù) Spring 比較推薦使用 TransactionTemplate 來對事務(wù)進行管理。

          2聲明式事務(wù):聲明式事務(wù)是建立在 AOP 之上的。其本質(zhì)是對方法前后進行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況“提交”或者“回滾”事務(wù)。

          兩種事務(wù)管理間的區(qū)別

          • 編程式事務(wù)允許用戶在代碼中精確定義事務(wù)的邊界。
          • 聲明式事務(wù)有助于用戶將操作與事務(wù)規(guī)則進行解耦,它是基于 AOP 交由 Spring 容器實現(xiàn),是開發(fā)人員只重點關(guān)注業(yè)務(wù)邏輯實現(xiàn)。
          • 編程式事務(wù)侵入到了業(yè)務(wù)代碼里面,但是提供了更加纖細的事務(wù)管理。而聲明式事務(wù)基于 AOP,所以既能起到事務(wù)作用,又可以不影響業(yè)務(wù)代碼的具體實現(xiàn)。一般而言比較推薦使用聲明式事務(wù),尤其是使用 @Transactional 注解,它能很好地幫助開發(fā)者實現(xiàn)事務(wù)的同時,也減少代碼開發(fā)量,且使代碼看起來更加清爽整潔。

          Spring 編程式事務(wù)

          一般來說編程式事務(wù)有兩種方法可以實現(xiàn):模板事務(wù)的方式(TransactionTemplate)平臺事務(wù)管理器方式(PlatformTransactionManager)

          • 模板事務(wù)的方式(TransactionTemplate):主要是使用 TransactionTemplate 類實現(xiàn)事務(wù),這也是 Spring 官方比較推薦的一種編程式使用方式;

          例:

          • ① 獲取模板對象 TransactionTemplate;
          • ② 選擇事務(wù)結(jié)果類型;
          • ③ 業(yè)務(wù)數(shù)據(jù)操作處理;
          • ④ 業(yè)務(wù)執(zhí)行完成事務(wù)提交或者發(fā)生異常進行回滾;

          其中 TransactionTemplate 的 execute 能接受兩種類型參數(shù)執(zhí)行事務(wù),分別為:

          ?TransactionCallback():?執(zhí)行事務(wù)且可以返回一個值。
          ?TransactionCallbackWithoutResult():?執(zhí)行事務(wù)沒有返回值。

          下面是使用 TransactionTemplate 的實例:

          @Service
          public?class?TransactionExample?{
          ??/**?1、獲取?TransactionTemplate?對象?**/
          ??@Autowired
          ??private?TransactionTemplate?transactionTemplate;
          ??
          ??public?void?addUser()?{
          ??????//?2、使用?TransactionCallback?或者?TransactionCallbackWithoutResult?執(zhí)行事務(wù)
          ??????transactionTemplate.execute(new?TransactionCallbackWithoutResult()?{
          ??????????@Override
          ??????????public?void?doInTransactionWithoutResult(TransactionStatus?transactionStatus)?{
          ??????????????try?{
          ??????????????????//?3、執(zhí)行業(yè)務(wù)代碼(這里進行模擬,執(zhí)行多個數(shù)據(jù)庫操作方法)
          ??????????????????userMapper.delete(1);
          ??????????????????userMapper.delete(2);
          ??????????????}?catch?(Exception?e)?{
          ??????????????????//?4、發(fā)生異常,進行回滾
          ??????????????????transactionStatus.setRollbackOnly();
          ??????????????}
          ??????????}
          ??????});
          ??}
          ??
          }

          • 平臺事務(wù)管理器方式(PlatformTransactionManager):這里使用最基本的事務(wù)管理局對事務(wù)進行管理,借助 Spring 事務(wù)的 PlatformTransactionManager 及 TransactionDefinition 和 TransactionStatus 三個核心類對事務(wù)進行操作。

          使用事務(wù)管理器方式實現(xiàn)事務(wù)步驟:

          • ① 獲取事務(wù)管理器 PlatformTransactionManager;
          • ② 獲取事務(wù)屬性定義對象 TransactionDefinition;
          • ③ 獲取事務(wù)狀態(tài)對象 TransactionStatus;
          • ④ 業(yè)務(wù)數(shù)據(jù)操作處理;
          • ⑤ 進行事務(wù)提交 commit 操作或者發(fā)生異常進行事務(wù)回滾 rollback 操作;
          @Service
          public?class?TransactionExample?{
          ????
          ????/**?1、獲取?PlatformTransactionManager?對象?**/
          ????@Autowired
          ????private?PlatformTransactionManager?platformTransactionManager;

          ????public?void?addUser()?{
          ????????//?2、獲取默認事務(wù)定義
          ????????DefaultTransactionDefinition?def?=?new?DefaultTransactionDefinition();
          ????????//?設(shè)置事務(wù)傳播行為
          ????????def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
          ????????//?3、根據(jù)事務(wù)定義對象設(shè)置的屬性,獲取事務(wù)狀態(tài)
          ????????TransactionStatus?status?=?platformTransactionManager.getTransaction(def);
          ????????try?{
          ????????????//?4、執(zhí)行業(yè)務(wù)代碼(這里進行模擬,執(zhí)行多個數(shù)據(jù)庫操作方法)
          ????????????userMapper.delete(1);
          ????????????userMapper.delete(2);
          ????????????//?5、事務(wù)進行提交
          ????????????platformTransactionManager.commit(status);
          ????????}?catch(Exception?e){
          ????????????//?5、事務(wù)進行回滾
          ????????????platformTransactionManager.rollback(status);
          ????????}
          ????}
          ????
          }

          Spring 聲明式事務(wù)

          聲明式事務(wù)(declarative transaction management)顧名思義就是使用聲明的方式來處理事務(wù)。該方式是基于 Spring AOP 實現(xiàn)的,將具體業(yè)務(wù)邏輯和事務(wù)處理解耦,其本質(zhì)是在執(zhí)行方法前后進行攔截,在方法開始之前創(chuàng)建或者加入一個事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。

          常用的聲明式事務(wù)使用方法

          常用的聲明式事務(wù)使用方法有

          • 1 XML
          • 2 @Transactional 注解

          兩種方法,由于近幾年 SpringBoot 的流行,提供很方便的自動化配置,致使 XML 方式已經(jīng)逐漸淘汰,比較推薦使用注解的方式

          @Transactional 的作用范圍

          注解 @Transactional 不僅僅可以添加在方法上面,還可以添加到類級別上,當(dāng)注解放在類級別時,表示所有該類的公共方法都配置相同的事務(wù)屬性信息。如果類級別配置了 @transactional,方法級別也配置了 @transactional,應(yīng)用程序會以方法級別的事務(wù)屬性信息來管理事務(wù),換言之,方法級別的事務(wù)屬性信息會覆蓋類級別的相關(guān)配置。

          @Transactional 注解中可配置參數(shù)
          • value:事務(wù)管理器,此配置項是設(shè)置 Spring 容器中的 Bean 名稱,這個 Bean 需要實現(xiàn)接口 PlatformTransactionManager。
          • transactionManager:事務(wù)管理器,該參數(shù)和 value 配置保持一致,是同一個東西。
          • isolation:事務(wù)隔離級別,默認為 Isolation.DEFAULT 級別
          • propagation:事務(wù)傳播行為,默認為 Propagation.REQUIRED
          • timeout:事務(wù)超時時間,單位為秒,默認值為-1,當(dāng)事務(wù)超時時會拋出異常,進行回滾操作。
          • readOnly:是否開啟只讀事務(wù),是否開啟只讀事務(wù),默認 false
          • rollbackForClassName:回滾事務(wù)的異常類名定義,同 rollbackFor,只是用類名定義。
          • noRollbackForClassName:指定發(fā)生哪些異常名不回滾事務(wù),參數(shù)為類數(shù)組,同 noRollbackFor,只是使用類的名稱定義。
          • rollbackFor:回滾事務(wù)異常類定義,當(dāng)方法中出異常,且異常類和該參數(shù)指定的類相同時,進行回滾操作,否則提交事務(wù)。
          • noRollbackFor:指定發(fā)生哪些異常不回滾事務(wù),當(dāng)方法中出異常,且異常類和該參數(shù)指定的類相同時,不回滾而是將繼續(xù)提交事務(wù)。
          示例
          @Transactional(propagation=Propagation.REQUIRED)
          public?void?test()?{
          ????????//todo?something
          }

          注意: 一般而言,不推薦將 @Transaction 配置到類上,因為這樣很可能使后來的維護人員必須強制使用事務(wù)。

          使用事務(wù)時需要注意的點

          • 1、遇到異常檢測不回滾,原因:默認RuntimeException級別才回滾,如果是Eexception級別的異常需要手動添加
          @Transactional(rollbackFor=Exception.class)
          • 2、捕捉異常后事物不生效,原因:捕捉處理了異常導(dǎo)致框架無法感知異常,自然就無法回滾了。建議:若非實際業(yè)務(wù)要求,則在業(yè)務(wù)層統(tǒng)一拋出異常,然后在控制層統(tǒng)一處理
          @Transactional(rollbackFor=Exception.class)
          public?void?test()?
          {
          ????try?{
          ?????????//業(yè)務(wù)代碼
          ????}?catch?(Exception?e)?{
          ????????//?TODO:?handle?exception
          ????}
          ???//主動捕捉異常導(dǎo)致框架無法捕獲,從而導(dǎo)致事物失效
          }

          總結(jié)

          本章主要講了 事務(wù)基本概念A(yù)CID是什么 ,臟讀、不可重復(fù)讀、幻讀 等等術(shù)語的介紹及例子 數(shù)據(jù)庫事務(wù)的隔離級別(4種), Spring事務(wù)傳播行為(7種),事務(wù)的實現(xiàn)實例和使用事務(wù)時需要注意的地方 ?通過這篇文章,小伙伴們應(yīng)該已經(jīng)對事務(wù)有了更深的了解吧 ,最后 歡迎關(guān)注我的公眾號:JAVA寶典 或者加我的微信 我們一起探討和學(xué)習(xí).


          瀏覽 130
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                    天天操,天天日,天天爽 | 99在线视频在线 | 毛片一区 | 日本三级日产三级国产三级 | 曰逼视频|