說到事務,作IT的確定都不陌生,會想到Transcation(開啓、提交、回滾)。做爲資深的IT工做者,對事務全面理解是一項基本功,固然對於正在邁向資深的我來講,也必須瞭解。下面就來談一下事務mysql
1、事務的概念sql
數據庫事務(Database Transaction) ,是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。 數據庫
2、事務的特性session
事務必須具有ACID四個特性併發
原子性(Atomicity): 一個事務的執行被視爲一個不可分割的單元,事務中的操做,要麼所有成功,要麼所有失敗回滾,不能只執行其中的一部分。性能
一致性(Consistency):一致性是指事務必須使數據庫從一個一致的狀態變到另外一個一致的狀態,也就是執行事務的先後狀態都必須處於一致的狀態。好比說A向B轉帳500,那麼A帳戶要減500,而B帳戶須要加500,這兩個事件最終的帳戶總額仍然沒有改變。測試
隔離性(Isolation):是指事務之間的行爲互不影響,在實際操做中,會受事務的隔離級別的影響。spa
持久性(Durability):事務提交以後,將數據持久到數據庫,即便系統出現問題,數據依然還在。命令行
3、事務的隔離級別事件
在說到事務的隔離特性時,提到事務的隔離性會受到隔離級別的影響。事務的隔離級別定義了事務之間的可見性,有人稱它爲事務的「自私」程度。主要分爲四種隔離級別
一、READ UNCOMMITTED(未提交讀)。
在此隔離級別下,若是事務A對數據進行修改,在沒有提交的狀況下,事務B也能夠看到該修改,這種問題稱爲髒讀。未提交讀的隔離級別較低,容易引發不少問題,通常不經常使用。
測試以下:(使用navicat鏈接mysql進行測試)
①首先要將隔離級別設置爲未提交讀狀態(如下實例都在global級別設置,也能夠設置session級別)
打開第一個命令行界面,用來專門設置隔離級別:
mysql> set @@global.tx_transaction='READ-UNCOMMITTED';
由於設置的是global級別的,因此在接下來的操做中,爲了能更好的演示效果,須要另開一個命令行窗口,在接下來的描述中,提到建立事務就表示新打開一個窗口。
②建立A事務:
首先要查看當前的隔離級別,確保是未提交讀狀態:
開啓事務,並執行查詢,能夠看到只有三條數據。結果以下:
③建立B事務:
也是先查看當前的隔離級別(如下測試都會在新打開命令行界面時查看隔離級別,後面就再也不敘述)
開啓事務,並插入一條數據,可是不提交。此時,在當前事務中能夠查詢到新增的數據:
④而後再回到A事務,執行查詢,此時在B事務還未提交時,就能夠查到新增的數據:
在A事務中讀到了B事務未提交的數據,稱此現象爲髒讀。
二、READ COMMITTED(提交讀)
在該隔離級別下,不會出現髒讀。當事務A對數據修改以後,只要在提交之後,事務B才能看到修改的數據。可是會出現不可重複讀問題,何謂不可重複讀?就是一個事務對同一行數據重複讀取兩次,可是卻獲得了不一樣的結果。
測試以下:
①設置隔離級別
mysql> set @@global.tx_isolation='READ-COMMITTED';
②建立事務A:
開啓事務,而後查詢數據
③建立事務B
開啓事務,接下來查看數據,跟事務A查到的數據一致。而後更新第二條數據。此時,不提交事務。
④在事務A中執行查詢命令,發現B事務更新的數據查不到:
⑤讓事務B提交,而後事務A再次執行查詢,此時就能夠查看到更新以後的數據:
在該隔離級別下,事務A讀到的內容是事務B提交後的數據,即事務A只能讀到事務B兩端的數據,至於事務B中間的其餘修改就讀不到了。如事務A能讀到剛開始的狀態,若是事務B在修改過程當中,剛開始把id=10的數據修改成‘cc’,沒有提交;而後又把id=11的數據改成‘dd’,依舊不提交;最後發現更新錯了,又把id=10的數據改成‘c’,id=11的數據改成‘d’,把id=9的數據改成‘bb’,提交。此時事務A只能讀到id=9的值變了,至於id=10和11的變化過程一無所知。這個就是與未提交讀的區別之處,未提交讀能看到這個變化過程,隨變化而變化。
三、REPEATABLE READ(可重複讀)
在該隔離級別下,不會出現不可重複讀的問題。事務B對數據作的修改,提交以後,對於先於B事務開啓的事務A來講,此修改仍然看不到。
測試以下:
①設置隔離級別
mysql> set@@global.tx_isolation='REPEATABLE-READ';
②建立事務A
開啓事務,而後執行查詢
③建立事務B
開啓事務B,先查詢數據,而後將第三條數據更新。此時不提交事務
④在事務A中進行查詢,沒法查看事務B修改的數據
⑤提交事務B,再在事務A中執行查詢,依然沒法看到更新的數據,查詢到的數據始終沒有改變
⑥將事務A提交,而後開啓新的事務,此時便可查看到更新後的數據
可重複讀解決了不可重複讀的問題,某個事務在執行期間,不管後續的其餘事務如何操做數據,都保持查詢結果不變,可是從新打開事務後,會讀到不同的數據。這就引出了幻讀的問題,所問幻讀就是事務在操做過程當中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺乏了第一次查詢中出現的數據。
四、SERIALIZABLE(可串行化)
這是隔離的最高級別,強制要求全部的事務串行執行,會對每行數據加鎖,這就形成大量鎖徵用問題,性能最差。
測試以下:
①設置隔離級別
mysql> set @@global.tx_isolation='SERIALIZABLE';
②建立事務A
開啓事務並執行查詢
③建立事務B
開啓事務並執行查詢,此時能夠查詢。可是若是更新數據時,事務處於等待狀態,由於事務A已經上鎖。當必定時間還沒法執行時,提示當前更新數據處於鎖狀態,沒法更新。
④當事務A提交後,處於等待狀態的事務B也會執行完。
可串行化解決了幻讀的問題,可是又引起了新的問題,死鎖。例如上述兩個事務,若是都不提交,那麼此時都將沒法進行後續操做。
綜合上述內容,四種隔離級別所解決的問題以下:
其性能以下:
即隔離級別越高,其併發性越低,性能越差。
4、小結
事務是開發中沒法避免的一個問題,因此熟悉事務的基本概念以及使用是很是重要的。固然本文也只是解析了事務的一角,還須要在從此的工做中繼續深刻剖析事務的應用。