事務的原子性(Atomicity)
事務的原子性指的是,事務中包含的程序做爲數據庫的邏輯工做單位,它所作的對數據改操做要所有執行,要麼所有不執行。這種特性稱爲原子性。 事務的原子性要求,若是把一個事務看做是一個程序,它要麼完整的被執行,要麼徹底執行。就是說事務的操縱序列或者徹底應用到數據庫或者徹底不影響數據庫。這種特性稱爲原子性 假如用戶在一個事務內完成了對數據庫的更新,這時全部的更新對外部世界必須是可見的,或者徹底沒有更新。前者稱事務已提交,後者稱事務撤銷。DBMS必須確保由成功提交的事物完成的全部操做在數據庫內有徹底的反映,而失敗的事務對數據庫徹底沒有影響html
-------------------------------------------------------------------------------------------------------------java
事務的一致性(Consistency)
指在一個事務執行以前和執行以後數據庫都必須處於一致性狀態。這種特性稱爲事務的一致性。假如數據庫的狀態知足全部的完整性約束,就說該數據庫是一致的。(打個比方,若是從 A 帳戶轉帳到 B 帳戶,不可能由於 A 帳戶扣了錢,而 B 帳戶沒有加錢吧)
一致性處理數據庫中對全部語義約束的保護。假如數據庫的狀態知足全部的完整性約束,就說該數據庫是一致的。例如,當數據庫處於一致性狀態S1時,對數據庫執行一
個事務,在事務執行期間假定數據庫的狀態是不一致的,當事務執行結束時,數據庫處在一致性狀態S2spring
-------------------------------------------------------------------------------------------------------------數據庫
隔離性(Isolation)
隔離性指併發的事務是相互隔離的。即一個事務內部的操做及正在操做的數據必須封鎖起來,不被企圖進行修改的事務看到 分離性是DBMS針對併發事務間的衝突提供的安全保證。DBMS能夠經過加鎖在併發執行的事務間提供不一樣級別的分離。假如併發交叉執行的事務沒有任何控制。操縱相同的共享對象的多個併發事務的執行可能引發異常狀況(打個比方,當咱們編寫了一條 update 語句,提交到數據庫的一剎那間,有可能別人也提交了一條 delete 語句到數據庫中。也許咱們都是對同一條記錄進行操做,能夠想象,若是不稍加控制,就會出大麻煩來。咱們必須保證數據庫操做之間是「隔離」的(線程之間有時也要作到隔離),彼此之間沒有任何干擾。這就是:隔離性(Isolation)。)
DBMS能夠在併發執行的事務間提供不一樣級別的分離。分離的級別和併發事務的吞吐量之間存在反比關係。較多事務的可分離性可能會帶來較高的衝突和較多的事務流產。流產的事務要消耗資源,這些資源必需要從新被訪問。所以,確保高分離級別的DBMS須要更多的開銷安全
要想真正的作到操做之間徹底沒有任何干擾是很難的,因而乎要制定一個規範。多線程
1.READ_UNCOMMITTED併發
2.READ_COMMITTEDide
3.REPEATABLE_READ性能
4.SERIALIZABLEidea
千萬不要去翻譯,那只是一個代號而已。從上往下,級別愈來愈高,併發性愈來愈差,安全性愈來愈高,反之則反。
-------------------------------------------------------------------------------------------------------------
持久性(Durability)
持久性意味着當系統或介質發生故障時,確保已提交事務的更新不能丟失。(打個比方,當咱們執行一條 insert 語句後,數據庫必需要保證有一條數據永久地存放在磁盤中,這個也算事務的一條特性, 它就是:持久性)即一旦一個事務提交,DBMS保證它對數據庫數據的改變應該是永久性的,耐得住任何系統故障
。持久性經過數據庫備份和恢復來保證 持久性意味着當系統或介質發生故障時,確保已提交事務的更新不能丟失。即對已提交事務的更新恢復。一旦一個事務被提交,DBMS必須保證提供適當的冗餘,使其耐的住系統故障。因此,持久性主要在於DBMS的恢復性能
-------------------------------------------------------------------------------------------------------------
2、三類數據讀問題和兩類數據更新問題
1.Dirty Read(髒讀)
餘額應該爲 1100 元纔對!請看 T6 時間點,事務 A 此時查詢餘額爲 900 元,這個數據就是髒數據,它是事務 A 形成的,明顯事務沒有進行隔離,滲過來了,亂套了。
2.Unrepeatable Read(不可重複讀)
事務 A 其實除了查詢了兩次之外,其餘什麼事情都沒有作,結果錢就從 1000 變成 0 了,這就是重複讀了。可想而知,這是別人乾的,不是我乾的。其實這樣也是合理的,畢竟事務 B 提交了事務,數據庫將結果進行了持久化,因此事務 A 再次讀取天然就發生了變化。
這種現象基本上是能夠理解的,但在有些變態的場景下倒是不容許的。畢竟這種現象也是事務之間沒有隔離所形成的,但咱們對於這種問題,彷佛能夠忽略。
3.Phantom Read(幻讀)
銀行工做人員,每次統計總存款,都看到不同的結果。不過這也確實也挺正常的,總存款增多了,確定是這個時候有人在存錢。可是若是銀行系統真的這樣設計,那算是玩完了。這一樣也是事務沒有隔離所形成的,但對於大多數應用系統而言,這彷佛也是正常的,能夠理解,也是容許的。銀行裏那些噁心的那些系統,要求很是嚴密,統計的時候,甚至會將全部的其餘操做給隔離開,這種隔離級別就算很是高了(估計要到 SERIALIZABLE 級別了)。
第一類丟失更新,A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。這種錯誤可能形成很嚴重的問題,經過下面的帳戶取款轉帳就能夠看出來:
可是,在當前的四種任意隔離級別中,都不會發生該狀況,否則絕對亂套,我都沒提交事務只是撤銷,就把別人的給覆蓋了,這也太恐怖了。
第二類丟失更新,B事務覆蓋A事務已經提交的數據,形成A事務所作操做丟失
概括一下,以上提到了事務併發所引發的跟讀取數據有關的問題,各用一句話來描述一下:
1.髒讀:事務 A 讀取了事務 B 未提交的數據,並在這個基礎上又作了其餘操做。
2.不可重複讀:事務 A 讀取了事務 B 已提交的更改數據。
3.幻讀:事務 A 讀取了事務 B 已提交的新增數據。
第一條是堅定抵制的,後兩條在大多數狀況下可不做考慮。
這就是爲何必需要有事務隔離級別這個東西了,它就像一面牆同樣,隔離不一樣的事務。看下面這個表格,您就清楚了不一樣的事務隔離級別能處理怎樣的事務併發問題:
根據您的實際需求,再參考這張表,最後肯定事務隔離級別,應該再也不是一件難事了。
如今來看看MySQL數據庫爲咱們提供的四種隔離級別:
① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。
② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
③ Read committed (讀已提交):可避免髒讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何狀況都沒法保證。
以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,固然級別越高,執行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(相似於Java多線程中的鎖)使得其餘的線程只能在鎖外等待,因此平時選用何種隔離級別應該根據實際狀況。在MySQL數據庫中默認的隔離級別爲Repeatable read (可重複讀)。
在MySQL數據庫中,支持上面四種隔離級別,默認的爲Repeatable read (可重複讀);而在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的爲Read committed級別。
例1:查看當前事務的隔離級別:
例2:將事務的隔離級別設置爲Read uncommitted級別:
或:
記住:設置數據庫的隔離級別必定要是在開啓事務以前!
若是是使用JDBC對數據庫的事務設置隔離級別的話,也應該是在調用Connection對象的setAutoCommit(false)方法以前。調用Connection對象的setTransactionIsolation(level)便可設置當前連接的隔離級別,至於參數level,可使用Connection對象的字段:
在JDBC中設置隔離級別的部分代碼:
後記:隔離級別的設置只對當前連接有效。對於使用MySQL命令窗口而言,一個窗口就至關於一個連接,當前窗口設置的隔離級別只對當前窗口中的事務有效;對於JDBC操做數據庫來講,一個Connection對象至關於一個連接,而對於Connection對象設置的隔離級別只對該Connection對象有效,與其餘連接Connection對象無關。
除了 JDBC 給咱們提供的事務隔離級別這種解決方案之外,還有哪些解決方案能夠完善事務管理功能呢?
不妨看看 spring 的解決方案吧,其實它是對 JDBC 的一個補充或擴展。它提供了一個很是重要的功能,就是:事務傳播行爲(TransactionPropagation Behavior)。
Spring 提供了 7 種事務傳播行爲。
1.PROPAGATION_REQUIRED
2.RROPAGATION_REQUIRES_NEW
3.PROPAGATION_NESTED
4.PROPAGATION_SUPPORTS
5.PROPAGATION_NOT_SUPPORTED
6.PROPAGATION_NEVER
7.PROPAGATION_MANDATORY
首先要明確的是,事務是從哪裏來?傳播到哪裏去?答案是,從方法 A 傳播到方法 B。Spring 解決的只是方法之間的事務傳播,那狀況就多了,好比:
這樣就是 4 種了,還有 3 種特殊狀況。仍是用個人 Style 給你們作一個分析吧:
@Transactional void A(){ } @Transactional void B(){ A(); }
假設事務從方法 A 傳播到方法 B,您須要面對方法 B,問本身一個問題:
方法 A 有事務嗎?
Spring 給咱們帶來了事務傳播行爲,這確實是一個很是強大而又實用的功能。除此之外,也提供了一些小的附加功能,好比:
1.事務超時(Transaction Timeout):爲了解決事務時間太長,消耗太多的資源,因此故意給事務設置一個最大時常,若是超過了,就回滾事務。
2.只事務(Readonly Transaction):爲了忽略那些不須要事務的方法,好比讀取數據,這樣能夠有效地提升一些性能。
最後,推薦你們使用 Spring 的註解式事務配置,而放棄 XML 式事務配置。由於註解實在是太優雅了,固然這一切都取決於您自身的狀況了。
在 Spring 配置文件中使用:
<tx:annotation-driven/>
在須要事務的方法上使用:
@Transactional public void xxx() { ... }
可在 @Transactional 註解中設置:事務隔離級別、事務傳播行爲、事務超時時間、是否只讀事務。
具體使用請參考個人另外一篇博客
https://my.oschina.net/idea813/blog/1582244
參考資料
https://www.cnblogs.com/lc-ant/p/3981834.html
http://blog.csdn.net/u014079773/article/details/52808193
http://blog.csdn.net/lovesomnus/article/details/44459675
https://www.cnblogs.com/fjdingsd/p/5273008.html