Transaction 也就是所謂的事務了,通俗理解就是一件事情。從小,父母就教育咱們,作事情要善始善終,不能半途而廢。 事務也是這樣,不能作一半就不作了,要麼作完,要麼就不作。也就是說,事務必須是一個不可分割的總體,就像咱們在化學課裏學到的原子,原子是構成物質的最小單位。因而,人們就概括出事務的第一個特性:原子性(Atomicity)。我靠,一點都不神祕嘛。mysql
特別是在數據庫領域,事務是一個很是重要的概念,除了原子性之外,它還有一個極其重要的特性,那就是:一致性(Consistency)。也就是說,執行完數據庫操做後,數據不會被破壞。打個比方,若是從 A 帳戶轉帳到 B 帳戶,不可能由於 A 帳戶扣了錢,而 B 帳戶沒有加錢吧。若是出現了這類事情,您必定會很是氣憤,什麼 diao 銀行啊!spring
當咱們編寫了一條 update 語句,提交到數據庫的一剎那間,有可能別人也提交了一條 delete 語句到數據庫中。也許咱們都是對同一條記錄進行操做,能夠想象,若是不稍加控制,就會出大麻煩來。咱們必須保證數據庫操做之間是「隔離」的(線程之間有時也要作到隔離),彼此之間沒有任何干擾。這就是:隔離性(Isolation)。要想真正的作到操做之間徹底沒有任何干擾是很難的,因而乎,天天上班打醬油的數據庫專家們,開始動腦筋了,「咱們要制定一個規範,讓各個數據庫廠商都支持咱們的規範!」,這個規範就是:事務隔離級別(Transaction Isolation Level)。能定義出這樣牛逼的規範真的挺不容易的,其實說白了就四個級別:sql
1.READ_UNCOMMITTED數據庫
2.READ_COMMITTED安全
3.REPEATABLE_READ併發
4.SERIALIZABLE高併發
千萬不要去翻譯,那只是一個代號而已。從上往下,級別愈來愈高,併發性愈來愈差,安全性愈來愈高,反之則反。工具
當咱們執行一條 insert 語句後,數據庫必需要保證有一條數據永久地存放在磁盤中,這個也算事務的一條特性, 它就是:持久性(Durability)。性能
概括一下,以上一共提到了事務的 4 條特性,把它們的英文單詞首字母合起來就是:ACID,這個就是傳說中的「事務 ACID 特性」!spa
真的是很是牛逼的特性啊!這 4 條特性,是事務管理的基石,必定要透徹理解。此外還要明確,這四個傢伙當中,誰纔是老大?
其實想一想也就清楚了:原子性是基礎,隔離性是手段,持久性是目的,真正的老大就是一致性。數據不一致了,就至關於「江湖亂套了」。因此說,這三個小弟都是跟着「一致性」這個老大混,爲他全心全意服務。
這四個傢伙當中,其實最難理解的反倒不是一致性,而是隔離性。由於它是保證一致性的重要手段,是工具,使用它不能有半點差池,不然後果自負!怪不得數據庫行業專家們都要來研究所謂的事務隔離級別了。其實,定義這四個級別就是爲了解決數據在高併發下所產生的問題,那又有哪些問題呢?
三類數據讀問題
1.Dirty Read(髒讀)
2.Unrepeatable Read(不可重複讀)
3.Phantom Read(幻讀)
兩類數據更新問題
1.第一類丟失更新
2.第二類丟失更新
首先看看「髒讀」,看到「髒」這個字,我就想到了噁心、骯髒。數據怎麼可能髒呢?其實也就是咱們常常說的「垃圾數據」了。好比說,有兩個事務,它們在併發執行(也就是競爭)。看看如下這個表格,您必定會明白我在說什麼:
餘額應該爲 1100 元纔對!請看 T6 時間點,事務 A 此時查詢餘額爲 900 元,這個數據就是髒數據,它是事務 A 形成的,明顯事務沒有進行隔離,滲過來了,亂套了。
因此髒讀這件事情是很是要不得的,必定要解決掉!讓事務之間隔離起來纔是硬道理。
不可重複讀又怎麼解釋呢?仍是用相似的例子來講明:
事務 A 其實除了查詢了兩次之外,其餘什麼事情都沒有作,結果錢就從 1000 變成 0 了,這就是重複讀了。可想而知,這是別人乾的,不是我乾的。其實這樣也是合理的,畢竟事務 B 提交了事務,數據庫將結果進行了持久化,因此事務 A 再次讀取天然就發生了變化。
這種現象基本上是能夠理解的,但在有些變態的場景下倒是不容許的。畢竟這種現象也是事務之間沒有隔離所形成的,但咱們對於這種問題,彷佛能夠忽略。
幻讀。我去!Phantom 這個單詞不就是「幽靈、鬼魂」嗎?剛看到這個單詞時,真的把個人小夥伴們都給驚呆了。怪不得這裏要翻譯成「幻讀」了,總不能翻譯成「幽靈讀」、「鬼魂讀」吧。其實意義就是鬼在讀,不是人在讀,或者說搞不清楚爲何,它就變了,很暈,真的很暈。仍是用一個示例來講話吧:
銀行工做人員,每次統計總存款,都看到不同的結果。不過這也確實也挺正常的,總存款增多了,確定是這個時候有人在存錢。可是若是銀行系統真的這樣設計,那算是玩完了。這一樣也是事務沒有隔離所形成的,但對於大多數應用系統而言,這彷佛也是正常的,能夠理解,也是容許的。銀行裏那些噁心的那些系統,要求很是嚴密,統計的時候,甚至會將全部的其餘操做給隔離開,這種隔離級別就算很是高了(估計要到 SERIALIZABLE 級別了)。
第一類丟失更新,A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。這種錯誤可能形成很嚴重的問題,經過下面的帳戶取款轉帳就能夠看出來:
可是,在當前的四種任意隔離級別中,都不會發生該狀況,否則絕對亂套,我都沒提交事務只是撤銷,就把別人的給覆蓋了,這也太恐怖了。
第二類丟失更新,B事務覆蓋A事務已經提交的數據,形成A事務所作操做丟失
概括一下,以上提到了事務併發所引發的跟讀取數據有關的問題,各用一句話來描述一下:
1.髒讀:事務 A 讀取了事務 B 未提交的數據,並在這個基礎上又作了其餘操做。
2.不可重複讀:事務 A 讀取了事務 B 已提交的更改數據。
3.幻讀:事務 A 讀取了事務 B 已提交的新增數據。
第一條是堅定抵制的,後兩條在大多數狀況下可不做考慮。
這就是爲何必需要有事務隔離級別這個東西了,它就像一面牆同樣,隔離不一樣的事務。看下面這個表格,您就清楚了不一樣的事務隔離級別能處理怎樣的事務併發問題:
根據您的實際需求,再參考這張表,最後肯定事務隔離級別,應該再也不是一件難事了。
JDBC 也提供了這四類事務隔離級別,但默認事務隔離級別對不一樣數據庫產品而言,倒是不同的。咱們熟知的MySQL 數據庫的默認事務隔離級別就是 READ_COMMITTED,Oracle、SQL Server、DB2等都有有本身的默認值。我認爲 READ_COMMITTED 已經能夠解決絕大多數問題了,其餘的就具體狀況具體分析吧。
提示:在 Java.sql.Connection 類中可查看全部的隔離級別。
咱們知道 JDBC 只是鏈接 Java 程序與數據庫的橋樑而已,那麼數據庫又是怎樣隔離事務的呢?其實它就是「鎖」這個東西。當插入數據時,就鎖定表,這叫「鎖表」;當更新數據時,就鎖定行,這叫「鎖行」。固然這個已經超出了咱們今天討論的範圍,因此仍是留點空間給咱們的 DBA 同窗吧,省得他沒啥好寫的了。
除了 JDBC 給咱們提供的事務隔離級別這種解決方案之外,還有哪些解決方案能夠完善事務管理功能呢?
不妨看看 spring 的解決方案吧,其實它是對 JDBC 的一個補充或擴展。它提供了一個很是重要的功能,就是:事務傳播行爲(TransactionPropagation 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 解決的只是方法之間的事務傳播,那狀況就多了,好比:
這樣就是 4 種了,還有 3 種特殊狀況。仍是用個人 Style 給你們作一個分析吧:
@Transactional void A(){ } @Transactional void B(){ A(); }
假設事務從方法 A 傳播到方法 B,您須要面對方法 B,問本身一個問題:
方法 A 有事務嗎?
看到我上面這段解釋,小夥伴們是否已經感覺到,被打通任督二脈的感受?多讀幾遍,體會一下,就是您本身的東西了。
須要注意的是 PROPAGATION_NESTED,不要被它的名字所欺騙,Nested(嵌套),因此凡是在相似方法 A 調用方法 B 的時候,在方法 B 上使用了這種事務傳播行爲,若是您真的那樣作了,那您就錯了。由於您錯誤地覺得 PROPAGATION_NESTED 就是爲方法嵌套調用而準備的,其實默認的 PROPAGATION_REQUIRED 就能夠幫助您,作您想要作的事情了。
Spring 給咱們帶來了事務傳播行爲,這確實是一個很是強大而又實用的功能。除此之外,也提供了一些小的附加功能,好比:
1.事務超時(Transaction Timeout):爲了解決事務時間太長,消耗太多的資源,因此故意給事務設置一個最大時常,若是超過了,就回滾事務。
2.只事務(Readonly Transaction):爲了忽略那些不須要事務的方法,好比讀取數據,這樣能夠有效地提升一些性能。
在 Spring 配置文件中使用:
<tx:annotation-driven/>
@Transactional
public void xxx() {
...
}
可在 @Transactional 註解中設置:事務隔離級別、事務傳播行爲、事務超時時間、是否只讀事務。
簡直是太完美了,太優雅了!
最後,有必要對本文的內容作一個總結,免費贈送一張高清無碼思惟導圖: