1. 程式人生 > >Spring 事物原始碼解析1-事務概念

Spring 事物原始碼解析1-事務概念

資料庫事務概述

 事務首先是一系列操作組成的工作單元,該工作單元內的操作是不可分割的,即要麼所有操作都做,要麼所有操作都不做,這就是事務。

1事務特性

事務必需滿足ACID(原子性、一致性、隔離性和永續性)特性,缺一不可:

    • 原子性(Atomicity):即事務是不可分割的最小工作單元,事務內的操作要麼全做,要麼全不做;
    • 一致性(Consistency):在事務執行前資料庫的資料處於正確的狀態,而事務執行完成後資料庫的資料還是處於正確的狀態,即資料完整性約束沒有被破壞;如銀行轉帳,A轉帳給B,必須保證A的錢一定轉給B,一定不會出現A的錢轉了但B沒收到,否則資料庫的資料就處於不一致(不正確)的狀態。
    • 隔離性(Isolation):併發事務執行之間無影響,在一個事務內部的操作對其他事務是不產生影響,這需要事務隔離級別來指定隔離性;
    • 永續性(Durability):事務一旦執行成功,它對資料庫的資料的改變必須是永久的,不會因比如遇到系統故障或斷電造成資料不一致或丟失。
2 常見的問題

在實際專案開發中資料庫操作一般都是併發執行的,即有多個事務併發執行,併發執行就可能遇到問題,目前常見的問題如下:

    • 丟失更新:兩個事務同時更新一行資料,最後一個事務的更新會覆蓋掉第一個事務的更新,從而導致第一個事務更新的資料丟失,這是由於沒有加鎖造成的;
    • 髒讀:一個事務看到了另一個事務未提交的更新資料;
    • 不可重複讀
      :在同一事務中,多次讀取同一資料卻返回不同的結果;也就是有其他事務更改了這些資料;
    • 幻讀:一個事務在執行過程中讀取到了另一個事務已提交的插入資料;即在第一個事務開始時讀取到一批資料,但此後另一個事務又插入了新資料並提交,此時第一個事務又讀取這批資料但發現多了一條,即好像發生幻覺一樣
事務屬性 3-1  隔離級別
    • 未提交讀(Read Uncommitted):最低隔離級別,一個事務能讀取到別的事務未提交的更新資料,很不安全,可能出現丟失更新、髒讀、不可重複讀、幻讀;
    • 提交讀(Read Committed):一個事務能讀取到別的事務提交的更新資料,不能看到未提交的更新資料,不可能可能出現丟失更新、髒讀,但可能出現不可重複讀、幻讀;
    • 可重複讀(Repeatable Read):保證同一事務中先後執行的多次查詢將返回同一結果,不受其他事務影響,可能可能出現丟失更新、髒讀、不可重複讀,但可能出現幻讀;
    • 序列化(Serializable):最高隔離級別,不允許事務併發執行,而必須序列化執行,最安全,不可能出現更新、髒讀、不可重複讀、幻讀。    
  • 隔離級別越高,資料庫事務併發執行效能越差,能處理的操作越少。因此在實際專案開發中為了考慮併發效能一般使用提交讀隔離級別,它能避免丟失更新和髒讀,儘管不可重複讀和幻讀不能避免,但可以在可能出現的場合使用悲觀鎖或樂觀鎖來解決這些問題。     

3-2  事務傳播行為 Spring管理的事務是邏輯事務,而且物理事務和邏輯事務最大差別就在於事務傳播行為,事務傳播行為用於指定在多個事務方法間呼叫時,事務是如何在這些方法間傳播的,Spring共支援7種傳播行為: Required:必須有邏輯事務,否則新建一個事務,使用PROPAGATION_REQUIRED指定,表示如果當前存在一個邏輯事務,則加入                    該邏輯事務,否則將新建一個邏輯事務,如圖9-2和9-3所示;

 

         圖9-2 Required傳播行為

 

       圖9-3 Required傳播行為丟擲異常情況

       在前邊示例中就是使用的Required傳播行為:

一、在呼叫userService物件的save方法時,此方法用的是Required傳播行為且此時Spring事務管理器發現還沒開啟邏輯事務,因此Spring管理器覺得開啟邏輯事務,

二、在此邏輯事務中呼叫了addressService物件的save方法,而在save方法中發現同樣用的是Required傳播行為,因此使用該已經存在的邏輯事務;

三、在返回到addressService物件的save方法,當事務模板類執行完畢,此時提交併關閉事務。

       因此userService物件的save方法和addressService的save方法屬於同一個物理事務,如果發生回滾,則兩者都回滾。

RequiresNew:建立新的邏輯事務,使用PROPAGATION_REQUIRES_NEW指定,表示每次都建立新的邏輯事務(物理事務也是不同的)如圖9-4和9-5所示:

 

圖9-4 RequiresNew傳播行為

 

圖9-5 RequiresNew傳播行為並丟擲異常

該傳播行為執行流程(正確提交情況):

一、當執行userService物件的save方法時,由於傳播行為是RequiresNew,因此建立一個新的邏輯事務(物理事務也是不同的);

二、當執行到addressService物件的save方法時,由於傳播行為是RequiresNew,因此首先暫停上一個邏輯事務並建立一個新的邏輯事務(物理事務也是不同的);

三、addressService物件的save方法執行完畢後,提交邏輯事務(並提交物理事務)並重新恢復上一個邏輯事務,繼續執行userService物件的save方法內的操作;

四、最後userService物件的save方法執行完畢,提交邏輯事務(並提交物理事務);

五、userService物件的save方法和addressService物件的save方法不屬於同一個邏輯事務且也不屬於同一個物理事務。

Supports:支援當前事務,使用PROPAGATION_SUPPORTS指定,指如果當前存在邏輯事務,就加入到該邏輯事務,如果當前沒有邏輯事務,就以非事務方式執行,如圖9-6和9-7所示:

 

圖9-6 Required+Supports傳播行為

 

       圖9-7 Supports+Supports傳播行為

NotSupported:不支援事務,如果當前存在事務則暫停該事務,使用PROPAGATION_NOT_SUPPORTED指定,即以非事務方式執行,如果當前存在邏輯事務,就把當前事務暫停,以非事務方式執行,如圖9-8和9-9所示:

 

       圖9-8 Required+NotSupported傳播行為

 

       圖9-9 Supports+NotSupported傳播行為

Mandatory:必須有事務,否則丟擲異常,使用PROPAGATION_MANDATORY指定,使用當前事務執行,如果當前沒有事務,則丟擲異常(IllegalTransactionStateException),如圖9-10和9-11所示:

 

       圖9-10 Required+Mandatory傳播行為

 

       圖9-11 Supports+Mandatory傳播行為

Never:不支援事務,如果當前存在是事務則丟擲異常,使用PROPAGATION_NEVER指定,即以非事務方式執行,如果當前存在事務,則丟擲異常(IllegalTransactionStateException),如圖9-12和9-13所示:

 

       圖9-12 Required+Never傳播行為

 

       圖9-13 Supports+Never傳播行為

Nested:巢狀事務支援,使用PROPAGATION_NESTED指定,如果當前存在事務,則在巢狀事務內執行,如果當前不存在事務,則建立一個新的事務,巢狀事務使用資料庫中的儲存點來實現,即巢狀事務回滾不影響外部事務,但外部事務回滾將導致巢狀事務回滾,如圖9-14和9-15所示:

 

       圖9-14 Required+Nested傳播行為

 

圖9-15 Nested+Nested傳播行為

Nested和RequiresNew的區別:

1、  RequiresNew每次都建立新的獨立的物理事務,而Nested只有一個物理事務;

2、  Nested巢狀事務回滾或提交不會導致外部事務回滾或提交,但外部事務回滾將導致巢狀事務回滾,而 RequiresNew由於都是全新的事務,所以之間是無關聯的;

3、  Nested使用JDBC 3的儲存點實現,即如果使用低版本驅動將導致不支援巢狀事務。

使用巢狀事務,必須確保具體事務管理器實現的nestedTransactionAllowed屬性為true,否則不支援巢狀事務,如DataSourceTransactionManager預設支援,而HibernateTransactionManager預設不支援,需要我們來開啟。

對於事務傳播行為我們只演示了Required和RequiresNew,其他傳播行為類似,如果對這些事務傳播行為不太會使用,請參考chapter9包下的TransactionTest測試類中的testPropagation方法,方法內有詳細示例。

3-3  事務超時     

  • 設定事務的超時時間,單位為秒,預設為-1表示使用底層事務的超時時間;

         使用如setTimeout(100)來設定超時時間,如果事務超時將丟擲org.springframework.transaction.TransactionTimedOutException異常並將當前事務標記為應該回滾,即超時後事務被自動回滾;

         可以使用具體事務管理器實現的defaultTimeout屬性設定預設的事務超時時間,如DataSourceTransactionManager. setDefaultTimeout(10)。

3-4  事務只讀     

  • 將事務標識為只讀,只讀事務不修改任何資料;

             對於JDBC只是簡單的將連線設定為只讀模式,對於更新將丟擲異常;

             而對於一些其他ORM框架有一些優化作用,如在Hibernate中,Spring事務管理器將執行“session.setFlushMode(FlushMode.MANUAL)”即指定Hibernate會話在只讀事務模式下不用嘗試檢測和同步持久物件的狀態的更新。

             如果使用設定具體事務管理的validateExistingTransaction屬性為true(預設false),將確保整個事務傳播鏈都是隻讀或都不是隻讀,如圖9-16是正確的事務只讀設定,而圖9-17是錯誤的事務只讀設定:

     

    圖9-16 正確的事務只讀設定

     

    圖9-17 錯誤的事務只讀設定

    如圖10-17,對於錯誤的事務只讀設定將丟擲IllegalTransactionStateException異常,並伴隨“Participating transaction with definition [……] is not marked as read-only……”資訊,表示參與的事務只讀屬性設定錯誤。

    4 事務型別

    資料庫事務型別有本地事務和分散式事務:

    • 本地事務:就是普通事務,能保證單臺數據庫上的操作的ACID,被限定在一臺資料庫上;
    • 分散式事務:涉及兩個或多個數據庫源的事務,即跨越多臺同類或異類資料庫的事務(由每臺數據庫的本地事務組成的),分散式事務旨在保證這些本地事務的所有操作的ACID,使事務可以跨越多臺資料庫;

    Java事務型別有JDBC事務和JTA事務:

    • JDBC事務:就是資料庫事務型別中的本地事務,通過Connection物件的控制來管理事務;
    • JTA事務:JTA指Java事務API(Java Transaction API),是Java EE資料庫事務規範, JTA只提供了事務管理介面,由應用程式伺服器廠商(如WebSphere Application Server)提供實現,JTA事務比JDBC更強大,支援分散式事務。

    Java EE事務型別有本地事務和全域性事務:

    • 本地事務:使用JDBC程式設計實現事務;
    • 全域性事務:由應用程式伺服器提供,使用JTA事務;

    按是否通過程式設計實現事務有宣告式事務和程式設計式事務;

    • 宣告式事務: 通過註解或XML配置檔案指定事務資訊;
    • 程式設計式事務:通過編寫程式碼實現事務。

    5  Spring提供的事務管理

    Spring框架最核心功能之一就是事務管理,而且提供一致的事務管理抽象,這能幫助我們:

    • 提供一致的程式設計式事務管理API,不管使用Spring JDBC框架還是整合第三方框架使用該API進行事務程式設計;
    • 無侵入式的宣告式事務支援。

    Spring支援宣告式事務和程式設計式事務事務型別。

相關推薦

Spring 事物原始碼解析1-事務概念

資料庫事務概述  事務首先是一系列操作組成的工作單元,該工作單元內的操作是不可分割的,即要麼所有操作都做,要麼所有操作都不做,這就是事務。 1事務特性 事務必需滿足ACID(原子性、一致性、隔離性和永續性)特性,缺一不可: 原子性(Atomicity

Spring IOC容器啟動流程原始碼解析(一)——容器概念詳解及原始碼初探

目錄 1. 前言 1.1 IOC容器到底是什麼 IOC和AOP是Spring框架的核心功能,而IOC又是AOP實現的基礎,因而可以說IOC是整個Spring框架的基石。那麼什麼是IOC?IOC即控制反轉,通俗的說就是讓Spring框架來幫助我們完成物件的依賴管理和生命週期控制等等工作。從面向物件的角度來說,

Spring-web原始碼解析之Filter-OncePerRequestFilter

轉自:  http://blog.csdn.net/ktlifeng/article/details/50630934 基於4.1.7.RELEASE 我們先看一個filter-mapping的配置 

BItCoin原始碼解析(1)——Base58編碼

看了https://blog.csdn.net/pure_lady/article/category/5858993/2好久,決定寫下開篇。 比特幣加密演算法一共有兩類:非對稱加密演算法(橢圓曲線加密演算法)和雜湊演算法(SHA256,RIMPED160演算法)。比特幣私鑰(private ke

Spring IOC DefaultListableBeanFactory解析1

       Spring的核心所在就是IOC以及AOP。但是我認為最為重要的還是IOC。關於IOC的基本概念我不涉及,反正就是將物件以及以來的權力交給Spring容器來處理。通常我們Spring入門的時候都會建立一個Java Bean。然後配置檔案去定義

spring-kafka原始碼解析

前言:         關於Kafka,是一個比較流行的MQ工具,也是多數公司比較常用的。有關於Kafka的一些基本內容讀者可以參考官方文件,瞭解一下生產者消費者的使用。kafka的搭建筆者也不再詳述,網路上有很多文章介紹。  

Google guava cache原始碼解析1--構建快取器(2)

此文已由作者趙計剛授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 CacheBuilder-->maximumSize(long size)     /**      * 

Google guava cache原始碼解析1--構建快取器(3)

此文已由作者趙計剛授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 下面介紹在LocalCache(CacheBuilder, CacheLoader)中呼叫的一些方法: CacheBuilder-->getConcurrencyLevel()

Tensorflow原始碼解析1 -- 核心架構和原始碼結構

1 主流深度學習框架對比 當今的軟體開發基本都是分層化和模組化的,應用層開發會基於框架層。比如開發Linux Driver會基於Linux kernel,開發Android app會基於Android Framework。深度學習也不例外,框架層為上層模型開發提

spring boot 原始碼解析57-actuator元件:info背後的密碼(全網獨家)

解析 我們平常訪問/info時會返回一些自定義的資訊,一般人只知道在application.properties中配置info.author=herry 開頭的配置,這樣就可以在訪問/info時,就會返回author: “herry”,但是如下的返回值是如何返

OkHttp 原始碼解析(1)

專案用到OkHttp,準備研究研究(OkHttp現在很火啊,Retrofit使用OkHttp,Volley支援替換底層http棧為OkHttp,甚至Google的最新原始碼裡,都用起了OkHttp,替換了原來用的HttpClient)。 OkHttp在網路

VS2015中STL原始碼解析1(霜之小刀)

VS2015中STL原始碼解析1(霜之小刀) QQ:2279557541 Email:[email protected] 1. 宣告 2 1. 宣告 本文參考了大量http:

JVM類載入機制(ClassLoader)原始碼解析(1)

其實JVM類載入機制,簡單地說就是類管理,也就是我們生成的class檔案。 三個步驟:裝載(load)、連結(link)、解析(Resolve)、還有初始化(Initialize) 關於網上有很多講解載入的方式,和呼叫的方式,還是幾個基本的classLoader,這裡就不在

spring boot原始碼解析

https://blog.csdn.net/dm_vincent/article/category/7079562https://blog.csdn.net/dm_vincent/article/details/76735888https://blog.csdn.net/dm

Spring MVC 原始碼解析

Spring MVC原始碼分析:  ①:DispatcherServlet是springmvc中的前端控制器(front controller),負責接收request並將request轉發給對應的處理元件.   ②:HanlerMapping是springmvc中完成url到cont

Mask RCNN 原始碼解析 (1)

Mask RCNN 屬於 RCNN這一系列的應該是比較最終的版本,融合多種演算法的思想,這裡對Mask RCNN從原始碼進行解析,主要寫幾篇文章,一個總結大的思路,其他文章整理細節。 這篇文章為了簡單,主要從前向傳播和後向傳播,分兩部分進行介紹,主要以資料的流動為主線,分析

Spring AOP原始碼解析(二)獲取增強器

一、方法入口 上一節中,Spring會建立兩個工廠來完成獲取增強方法的功能: AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause()

比特幣原始碼解析(1)

0x00 寫在前面 研究了這麼久的區塊鏈卻一直都沒有完整的看過一個區塊鏈專案的程式碼,甚至還一度沉迷各種ICO,每天看著各種貨幣層出不窮,跌跌漲漲,起起伏伏,不亦樂乎。現在看來,也許整體來講賺了點小錢,可是那又有什麼意義呢?終究不是長久之計。這兩天終於靜下來大

spring boot 原始碼解析[email protected]

前言 之前在分析spring boot 原始碼時匯出可見@ConditionalOnBean 之類的註解,那麼它到底是如何使用的以及其工作流程如何,我們這裡就圍繞以下幾點來分析: @Conditional系列與Condition的關係 @Condition

Java原始碼解析(1) —— Object

Java基類Object   java.lang.Object,Java所有類的父類,在你編寫一個類的時候,若無指定父類(沒有顯式extends一個父類)編譯器(一般編譯器完成該步驟)會預設的新增Object為該類的父類(可以將該類反編譯看其位元組碼,不過貌似