Transaction 那點事兒,Spring事務管理

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

Transaction 也就是所謂的事務了,通俗理解就是一件事情。從小,父母就教育我們,做事情要有始有終,不能半途而廢。?事務也是這樣,不能做一般就不做了,要么做完,要么就不做。也就是說,事務必須是一個不可分割的整體,就像我們在化學課里學到的原子,原子是構成物質的最小單位。于是,人們就歸納出事務的第一個特性:原子性(Atomicity)。我靠,一點都不神秘嘛。

特別是在數據庫領域,事務是一個非常重要的概念,除了原子性以外,它還有一個極其重要的特性,那就是:一致性(Consistency)。也就是說,執行完數據庫操作后,數據不會被破壞。打個比方,如果從 A 賬戶轉賬到 B 賬戶,不可能因為 A 賬戶扣了錢,而 B 賬戶沒有加錢吧。如果出現了這類事情,您一定會非常氣憤,什么 diao 銀行啊!

當我們編寫了一條 update 語句,提交到數據庫的一剎那間,有可能別人也提交了一條 delete 語句到數據庫中。也許我們都是對同一條記錄進行操作,可以想象,如果不稍加控制,就會出大麻煩來。我們必須保證數據庫操作之間是“隔離”的(線程之間有時也要做到隔離),彼此之間沒有任何干擾。這就是:隔離性(Isolation)。要想真正的做到操作之間完全沒有任何干擾是很難的,于是乎,每天上班打醬油的數據庫專家們,開始動腦筋了,“我們要制定一個規范,讓各個數據庫廠商都支持我們的規范!”,這個規范就是:事務隔離級別(Transaction Isolation Level)。能定義出這樣牛逼的規范真的挺不容易的,其實說白了就四個級別:

  1. READ_UNCOMMITTED
  2. READ_COMMITTED
  3. REPEATABLE_READ
  4. SERIALIZABLE

千萬不要去翻譯,那只是一個代號而已。從上往下,級別越來越高,并發性越來越差,安全性越來越高,反之則反。

當我們執行一條 insert 語句后,數據庫必須要保證有一條數據永久地存放在磁盤中,這個也算事務的一條特性,?它就是:持久性(Durability)。

歸納一下,以上一共提到了事務的 4 條特性,把它們的英文單詞首字母合起來就是:ACID,這個就是傳說中的“事務 ACID 特性”!

真的是非常牛逼的特性啊!這 4 條特性,是事務管理的基石,一定要透徹理解。此外還要明確,這四個家伙當中,誰才是老大?

其實想想也就清楚了:原子性是基礎,隔離性是手段,持久性是目的,真正的老大就是一致性。數據不一致了,就相當于“江湖亂套了,流氓戴胸罩”。所以說,這三個小弟都是跟著“一致性”這個老大混,為他全心全意服務。

這四個家伙當中,其實最難理解的反倒不是一致性,而是隔離性。因為它是保證一致性的重要手段,是工具,使用它不能有半點差池,否則后果自負!怪不得數據庫行業專家們都要來研究所謂的事務隔離級別了。其實,定義這四個級別就是為了解決數據在高并發下所產生的問題,那又有哪些問題呢?

  1. Dirty Read(臟讀)
  2. Unrepeatable Read(不可重復讀)
  3. Phantom Read(幻讀)

首先看看“臟讀”,看到“臟”這個字,我就想到了惡心、骯臟。數據怎么可能臟呢?其實也就是我們經常說的“垃圾數據”了。比如說,有兩個事務,它們在并發執行(也就是競爭)。看看以下這個表格,您一定會明白我在說什么:

?

時間事務 A(存款)事務 B(取款)
T1開始事務?
T2?開始事務
T3?查詢余額(1000 元)
T4?取出 1000 元(余額 0 元)
T5查詢余額(0 元)?
T6?撤銷事務(余額恢復為 1000 元)
T7存入 500 元(余額 500 元)?
T8提交事務?


余額應該為 1500 元才對!請看 T5 時間點,事務 A 此時查詢余額為 0 元,這個數據就是臟數據,它是事務 B 造成的,明顯事務沒有進行隔離,滲過來了,亂套了。

所以臟讀這件事情是非常要不得的,一定要解決掉!讓事務之間隔離起來才是硬道理。

那第 2 條,不可重復讀又怎么解釋呢?還是用類似的例子來說明:

?

時間事務 A(存款)事務 B(取款)
T1開始事務?
T2?開始事務
T3?查詢余額(1000 元)
T4查詢余額(1000 元)?
T5?取出 1000 元(余額 0 元)
T6?提交事務
T7查詢余額(0 元)?


事務 A 其實除了查詢了兩次以外,其他什么事情都沒有做,結果錢就從 1000 變成 0 了,這就是重復讀了。可想而知,這是別人干的,不是我干的。其實這樣也是合理的,畢竟事務 B 提交了事務,數據庫將結果進行了持久化,所以事務 A 再次讀取自然就發生了變化。

這種現象基本上是可以理解的,但在有些變態的場景下卻是不允許的。畢竟這種現象也是事務之間沒有隔離所造成的,但我們對于這種問題,似乎可以忽略。

最后一條,幻讀。我去!Phantom 這個單詞不就是“幽靈、鬼魂”嗎?剛看到這個單詞時,真的把我的小弟弟都給驚呆了。怪不得這里要翻譯成“幻讀”了,總不能翻譯成“幽靈讀”、“鬼魂讀”吧。其實意義就是鬼在讀,不是人在讀,或者說搞不清楚為什么,它就變了,很暈,真的很暈。還是用一個示例來說話吧:

時間事務 A(統計總存款)事務 B(存款)
T1開始事務?
T2?開始事務
T3統計總存款(10000 元)?
T4?存入 100 元
T5?提交事務
T6統計總存款(10100 元)?


銀行工作人員,每次統計總存款,都看到不一樣的結果。不過這也確實也挺正常的,總存款增多了,肯定是這個時候有人在存錢。但是如果銀行系統真的這樣設計,那算是玩完了。這同樣也是事務沒有隔離所造成的,但對于大多數應用系統而言,這似乎也是正常的,可以理解,也是允許的。銀行里那些惡心的那些系統,要求非常嚴密,統計的時候,甚至會將所有的其他操作給隔離開,這種隔離級別就算非常高了(估計要到 SERIALIZABLE 級別了)。

歸納一下,以上提到了事務并發所引起的跟讀取數據有關的問題,各用一句話來描述一下:

  1. 臟讀:事務 A 讀取了事務 B 未提交的數據,并在這個基礎上又做了其他操作。
  2. 不可重復讀:事務 A 讀取了事務 B?已提交的更改數據。
  3. 幻讀:事務 A 讀取了事務 B 已提交的新增數據。

第一條是堅決抵制的,后兩條在大多數情況下可不作考慮。

這就是為什么必須要有事務隔離級別這個東西了,它就像一面墻一樣,隔離不同的事務。看下面這個表格,您就清楚了不同的事務隔離級別能處理怎樣的事務并發問題:

?

事務隔離級別臟讀不可重復讀幻讀
READ_UNCOMMITTED允許允許允許
READ_COMMITTED禁止允許允許
REPEATABLE_READ禁止禁止允許
SERIALIZABLE禁止禁止禁止


根據您的實際需求,再參考這張表,最后確定事務隔離級別,應該不再是一件難事了。

JDBC 也提供了這四類事務隔離級別,但默認事務隔離級別對不同數據庫產品而言,卻是不一樣的。我們熟知的 MySQL 數據庫的默認事務隔離級別就是?READ_COMMITTED,Oracle、SQL Server、DB2等都有有自己的默認值。我認為 READ_COMMITTED 已經可以解決絕大多數問題了,其他的就具體情況具體分析吧。

若對其他數據庫的默認事務隔離級別不太清楚,可以使用以下代碼來獲取:


DatabaseMetaData meta = DBUtil.getDataSource().getConnection().getMetaData();
int defaultIsolation = meta.getDefaultTransactionIsolation();

提示:在 java.sql.Connection 類中可查看所有的隔離級別。

我們知道 JDBC 只是連接 Java 程序與數據庫的橋梁而已,那么數據庫又是怎樣隔離事務的呢?其實它就是“鎖”這個東西。當插入數據時,就鎖定表,這叫“鎖表”;當更新數據時,就鎖定行,這叫“鎖行”。當然這個已經超出了我們今天討論的范圍,所以還是留點空間給我們的 DBA 同學吧,免得他沒啥好寫的了。

除了 JDBC 給我們提供的事務隔離級別這種解決方案以外,還有哪些解決方案可以完善事務管理功能呢?

不妨看看 Spring 的解決方案吧,其實它是對 JDBC 的一個補充或擴展。它提供了一個非常重要的功能,就是:事務傳播行為(Transaction Propagation Behavior)。

確實夠牛逼的,Spring 一下子就提供了 7 種事務傳播行為,這 7 種行為一出現,真的是亮瞎了我的狗眼!

  1. PROPAGATION_REQUIRED
  2. RROPAGATION_REQUIRES_NEW
  3. PROPAGATION_NESTED
  4. PROPAGATION_SUPPORTS
  5. PROPAGATION_NOT_SUPPORTED
  6. PROPAGATION_NEVER
  7. PROPAGATION_MANDATORY

看了?Spring 參考手冊之后,更是暈了,這到底是在干嘛?

首先要明確的是,事務是從哪里來?傳播到哪里去?答案是,從方法 A 傳播到方法 B。Spring 解決的只是方法之間的事務傳播,那情況就多了,比如:

  1. 方法 A 有事務,方法 B 也有事務。
  2. 方法 A 有事務,方法 B 沒有事務。
  3. 方法 A 沒有事務,方法 B 有事務。
  4. 方法 A 沒有事務,方法 B 也沒有事務。?

這樣就是 4 種了,還有 3 種特殊情況。還是用我的 Style 給大家做一個分析吧:

假設事務從方法 A 傳播到方法 B,您需要面對方法 B,問自己一個問題:

方法 A 有事務嗎?

  1. 如果沒有,就新建一個事務;如果有,就加入當前事務。這就是?PROPAGATION_REQUIRED,它也是 Spring 提供的默認事務傳播行為,適合絕大多數情況。
  2. 如果沒有,就新建一個事務;如果有,就將當前事務掛起。這就是?RROPAGATION_REQUIRES_NEW,意思就是創建了一個新事務,它和原來的事務沒有任何關系了。
  3. 如果沒有,就新建一個事務;如果有,就在當前事務中嵌套其他事務。這就是?PROPAGATION_NESTED,也就是傳說中的“嵌套事務”了,所嵌套的子事務與主事務之間是有關聯的(當主事務提交或回滾,子事務也會提交或回滾)。
  4. 如果沒有,就以非事務方式執行;如果有,就使用當前事務。這就是?PROPAGATION_SUPPORTS,這種方式非常隨意,沒有就沒有,有就有,有點無所謂的態度,反正我是支持你的。
  5. 如果沒有,就以非事務方式執行;如果有,就將當前事務掛起。這就是?PROPAGATION_NOT_SUPPORTED,這種方式非常強硬,沒有就沒有,有我也不支持你,把你掛起來,不鳥你。
  6. 如果沒有,就以非事務方式執行;如果有,就拋出異常。這就是?PROPAGATION_NEVER,這種方式更猛,沒有就沒有,有了反而報錯,確實夠牛的,它說:我從不支持事務!
  7. 如果沒有,就拋出異常;如果有,就使用當前事務。這就是?PROPAGATION_MANDATORY,這種方式可以說是牛逼中的牛逼了,沒有事務直接就報錯,確實夠狠的,它說:我必須要有事務!

看到我上面這段解釋,小伙伴們是否已經感受到,被打通任督二脈的感覺?多讀幾遍,體會一下,就是您自己的東西了。

需要注意的是?PROPAGATION_NESTED,不要被它的名字所欺騙,Nested(嵌套),所以凡是在類似方法 A 調用方法 B 的時候,在方法 B 上使用了這種事務傳播行為,如果您真的那樣做了,那您就錯了。因為您錯誤地以為?PROPAGATION_NESTED 就是為方法嵌套調用而準備的,其實默認的?PROPAGATION_REQUIRED 就可以幫助您,做您想要做的事情了。

Spring 給我們帶來了事務傳播行為,這確實是一個非常強大而又實用的功能。除此以外,也提供了一些小的附加功能,比如:

  1. 事務超時(Transaction Timeout):為了解決事務時間太長,消耗太多的資源,所以故意給事務設置一個最大時常,如果超過了,就回滾事務。
  2. 只讀事務(Readonly Transaction):為了忽略那些不需要事務的方法,比如讀取數據,這樣可以有效地提高一些性能。

最后,推薦大家使用 Spring 的注解式事務配置,而放棄 XML 式事務配置。因為注解實在是太優雅了,當然這一切都取決于您自身的情況了。

在 Spring 配置文件中使用:

...
<tx:annotation-driven />
...

在需要事務的方法上使用:


@Transactional
public void xxx() {...
}

可在?@Transactional 注解中設置:事務隔離級別、事務傳播行為、事務超時時間、是否只讀事務。

簡直是太完美了,太優雅了!

最后,有必要對本文的內容做一個總結,免費贈送一張高清無碼思維導圖:

期盼您的對本文的評價!感謝您的關注與支持!

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452022.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡爬蟲--12.【XPath實戰】獲取百度貼吧中的圖片

用XPath來做一個簡單的爬蟲&#xff0c;我們嘗試爬取某個貼吧里的所有帖子&#xff0c;并且將該這個帖子里每個樓層發布的圖片下載到本地。 #codingutf-8 import requests from lxml import etree import jsonclass Tieba:def __init__(self,tieba_name):self.tieba_name tie…

合并分ER圖產生的沖突

合并分E-R圖 各個局部應用所面向的問題不同&#xff0c;各個子系統的E-R圖之間必定會存在許多不一致的地方&#xff0c;稱之為沖突。 子系統E-R圖之間的沖突主要有三類&#xff1a; ①屬性沖突 ②命名沖突 ③結構沖突①屬性沖突 屬性域沖突&#xff0c;即屬性值的類型、取值范圍…

8.類定義、屬性、初始化和析構

類定義 類 是一個獨立存放變量(屬性/方法)的空間 封裝&#xff1a; 類可以把各種對象組織在一起&#xff0c;作為類的屬性&#xff0c;通過 . (點)運算符來調用類中封裝好的對象 屬性&#xff1a; 變量在類中稱為屬性&#xff0c;但是類中的屬性不僅僅只包含變量&#x…

GPL以及Copyleft協議使用率下降明顯

根據最新的協議數據分析&#xff0c;不光是GPL&#xff0c;另外一些copyleft&#xff08;AGPL&#xff0c;LGPL 等等&#xff09;協議的使用率在不斷下降&#xff0c;并且下降的速度越來越快。 這結果是在意料之中的&#xff0c;因為GPL非常的復雜。越來越多的個人和企業將選擇…

概念模型和關系模型

ER模型&#xff08;邏輯模型&#xff09; ER模型的基本元素是&#xff1a;實體、聯系和屬性 實體&#xff1a;是一個數據對象&#xff0c;指應用中可以區別的客觀存在的事物。&#xff08;ER模型中的實體往往是指實體集&#xff09; 實體集&#xff1a;指同一類實體構成的集合…

iOS AutoLayout使用技巧

關于ContentCompressionResistance&#xff0c; ContentHugging運用 如下圖效果圖&#xff0c;兩個Label并列在同一排上&#xff0c;左邊label自適應&#xff0c;右邊label&#xff08;紅色&#xff09;要使得內容全部展示&#xff0c;如果左邊label內容很少&#xff0c;那么右…

網絡爬蟲--13.數據提取之JSON與JsonPATH

文章目錄一. 前言二. JSON三. json.loads()四. json.dumps()五. json.dump()六. json.load()七. JsonPath八. JsonPath與XPath語法對比九. 案例分析一. 前言 JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式&#xff0c;它使得人們很容易的進行閱讀和編寫。同時…

vs2017生成sqlserver 2017項目出現.Net SqlClient Data Provider: Msg 10343

一、使用vs2017生成sqlserver 2017項目時由于添加的程序集(CLR集成&#xff0c;可以參考后面給出的鏈接進行理解) &#xff0c;由于安全權限的配置不正確引發以下的問題: SQL72014: .Net SqlClient Data Provider: Msg 10343, Level 14, State 1, Line 1 針對帶有 SAFE 或 EXT…

數據庫系統常用的存取方法

1. B樹索引存取方法 2. Hash索引存取方法 3. 聚簇存取方法

創建型模式二:工廠方法模式

1. 工廠模式介紹 工廠模式&#xff08;Factory Pattern&#xff09;的意義就跟它的名字一樣&#xff0c;在面向對象程序設計中&#xff0c;工廠通常是一個用來創建其他對象的對象。工廠模式根據不同的參數來實現不同的分配方案和創建對象。 在工廠模式中&#xff0c;我們在創建…

spring 的4種事務管理(1種編程式+3種聲明式)

見&#xff1a;http://blog.csdn.net/sinat_25926481/article/details/48208619 Spring的4種事務管理&#xff08;1種編程式事務三種聲明事務&#xff09; 一、Spring事務的介紹 二、編程式事務xml的配置 注入后直接在service層調用模板的方法使用 三、基于AOP方式的聲明式事務…

如何創造出更優秀的用戶體驗?

對于互聯網公司來說&#xff0c;用戶體驗起到至關重要的作用&#xff0c;能否給用戶留下深刻的印象&#xff1b;開發出的產品是否實用、易用&#xff1f;等等這些都是開發者必將思考的話題。當有用性一樣的時候&#xff0c;大家的競爭重點就是易用性了&#xff0c;這就是互聯網…

java并發編程實戰-第三章-對象的共享

3.1可見性 首先我們需要知道的是&#xff0c;java的線程都有自己獨立的緩存&#xff0c;線程之間進行共享變量的交互是通過自身和緩存和主存的交互實現的。如果線程的每次更改緩存都刷入主存&#xff0c;主存每次被一個線程的緩存修改&#xff0c;都通知所有的線程刷新自身的緩…

GitHub(從安裝到使用)

一、安裝Git for Windows&#xff08;又名msysgit&#xff09; 下載地址: https://git-for-windows.github.io/ 在官方下載完后&#xff0c;安裝到Windows Explorer integration的時候&#xff0c;將選項中將“Git Bash here”和“Git GUI here”打對勾。 然后就一直next直到Fi…

Spring事務配置的五種方式和spring里面事務的傳播屬性和事務隔離級別、不可重復讀與幻讀的區別

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 spring事務配置的五種方式 前段時間對Spring的事務配置做了比較深入的研究&#xff0c;在此之間對Spring的事務配置雖說也配置過&#x…

Google編程之夏入圍項目公布

Google編程之夏&#xff08;Google Summer of Code&#xff09;&#xff0c;是由Google公司所主辦的年度程式設計比賽&#xff0c;第一屆從2005年開始。“Summer of Code”之名取自1967年的“夏日之愛”&#xff08;Summer of Love&#xff09;風潮。比賽的主要目的是鼓勵學生參…

普通索引 唯一索引 主鍵索引 候選索引

普通索引 最基本的索引類型&#xff0c;沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建&#xff1a; 創建索引&#xff0c;例如CREATE INDEX <索引的名字> ON tablename (列的列表)&#xff1b; 修改表&#xff0c;例如ALTER TABLE tablename ADD INDEX [索引…

Android 基于注解IOC組件化/模塊化的架構實踐

當前參與的項目歷史也很久遠&#xff0c;第一行代碼據說是寫于2014年的某一天&#xff0c;那時Android用的ide還是Eclipse、那時Android還沒有很好的架構指導&#xff08;mvp、mvvm&#xff09;、那時Android最新的版本是5.0、那時Android的Material Design還沒流行……背景隨著…

網絡爬蟲--14.【糗事百科實戰】

文章目錄一. 要求二. 參考代碼一. 要求 爬取糗事百科段子&#xff0c;假設頁面的URL是 http://www.qiushibaike.com/8hr/page/1 使用requests獲取頁面信息&#xff0c;用XPath / re 做數據提取 獲取每個帖子里的用戶頭像鏈接、用戶姓名、段子內容、點贊次數和評論次數 保存到…

bzoj 5369: [Pkusc2018]最大前綴和

Description 小C是一個算法競賽愛好者&#xff0c;有一天小C遇到了一個非常難的問題&#xff1a;求一個序列的最大子段和。 但是小C并不會做這個題&#xff0c;于是小C決定把序列隨機打亂&#xff0c;然后取序列的最大前綴和作為答案。 小C是一個非常有自知之明的人&#xff0c…