MySQL的事務和隔離級別

原文首發自我的博客:http://www.toxingwang.com/database/mysql/1454.htmlhtml

1、什麼是事務?

數據庫的事物,是指將一系列的操做做爲一個邏輯單元來執行,即加入由十條SQL語句組成的一個事物,則要麼則十條都執行成功,要麼都不執行!事務處理能夠確保除非事務性單元內的全部操做都成功完成,不然不會永久更新面向數據的資源。一個邏輯工做單元要成爲事務,必須知足所謂的ACID(原子性、一致性、隔離性和持久性)屬性。mysql

爲何要用事務?

假想一下,沒有事務的狀況會發生什麼狀況:你經過網銀向別人轉的帳戶轉錢,結果執行到一半,出現故障(如服務器宕機),你的錢被減小了,而你轉帳的對方帳戶錢卻沒有加上去!錢消失了!sql

若是有事務會是怎麼樣的?當執行到一半出錯,那已經執行的也會被撤銷,保障ACID!數據庫

2、事務的ACID屬性:

原子性(atomicity)

事務必須是原子工做單元;對於其數據修改,要麼全都執行,要麼全都不執行。一般,與某個事務關聯的操做具備共同的目標,而且是相互依賴的。若是系統只執行這些操做的一個子集,則可能會破壞事務的整體目標。原子性消除了系統處理操做子集的可能性。安全

一致性(consistency)

事務在完成時,必須使全部的數據都保持一致狀態。在相關數據庫中,全部規則都必須應用於事務的修改,以保持全部數據的完整性。事務結束時,全部的內部數據結構(如 B 樹索引或雙向鏈表)都必須是正確的。某些維護一致性的責任由應用程序開發人員承擔,他們必須確保應用程序已強制全部已知的完整性約束。例如,當開發用於轉賬的應用程序時,應避免在轉賬過程當中任意移動小數點。服務器

隔離性(isolation)

由併發事務所做的修改必須與任何其它併發事務所做的修改隔離。事務查看數據時數據所處的狀態,要麼是另外一併發事務修改它以前的狀態,要麼是另外一事務修改它以後的狀態,事務不會查看中間狀態的數據。這稱爲隔離性,由於它可以從新裝載起始數據,而且重播一系列事務,以使數據結束時的狀態與原始事務執行的狀態相同。當事務可序列化時將得到最高的隔離級別。在此級別上,從一組可並行執行的事務得到的結果與經過連續運行每一個事務所得到的結果相同。因爲高度隔離會限制可並行執行的事務數,因此一些應用程序下降隔離級別以換取更大的吞吐量。數據結構

持久性(durability)

事務完成以後,它對於系統的影響是永久性的。該修改即便出現致命的系統故障也將一直保持。保證事務的持久性,主要經過以下方式完成:併發

  • 事務提交以前就已經寫入數據至持久性存儲;ide

  • 經過事務日誌協助完成(事務日誌使用連續IO,所以寫入很是快)性能

3、MySQL對事務的支持狀況:

MySQL數據庫中,只有使用InnoDB 和 BDB存儲引擎才支持事務,而其餘存儲引擎(如經常使用的MyISAM引擎)是不支持事務的,這點特別須要注意。

4、事務的隔離級別詳解

SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級通常支持更高的併發處理,並擁有更低的系統開銷。

Read Uncommitted(讀取未提交內容)

在該隔離級別,全部事務均可以看到其餘未提交事務的執行結果。本隔離級別不多用於實際應用,由於它的性能也不比其餘級別好多少。讀取未提交的數據,也被稱之爲髒讀(Dirty Read)。

Read Committed(讀取提交內容)

這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它知足了隔離的簡單定義:一個事務只能看見已經提交事務所作的改變。這種隔離級別 也支持所謂的不可重複讀(Nonrepeatable Read),由於同一事務的其餘實例在該實例處理其間可能會有新的commit,因此同一select可能返回不一樣結果。

Repeatable Read(可重讀)

這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在併發讀取數據時,會看到一樣的數據行。不過理論上,這會致使另外一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一範圍的數據行時,另外一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的「幻影」 行。InnoDB和Falcon存儲引擎經過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。

Serializable(可串行化)

這是最高的隔離級別,它經過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每一個讀的數據行上加上共享鎖。在這個級別,可能致使大量的超時現象和鎖競爭。

這四種隔離級別採起不一樣的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。例如:

髒讀(Drity Read):某個事務已更新一份數據,另外一個事務在此時讀取了同一份數據,因爲某些緣由,前一個RollBack了操做,則後一個事務所讀取的數據就會是不正確的。

不可重複讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這多是兩次查詢過程當中間插入了一個事務更新的原有的數據。

幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例若有一個事務查詢了幾列(Row)數據,而另外一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。

在MySQL中,實現了這四種隔離級別,分別有可能產生問題以下所示:

圖片

下面,將利用MySQL的客戶端程序,分別測試幾種隔離級別。測試數據庫爲test,表爲tx;表結構:

id int

num int

兩個命令行客戶端分別爲A,B;不斷改變A的隔離級別,在B端修改數據。

(一)、將A的隔離級別設置爲read uncommitted(未提交讀)

在B未更新數據以前:

客戶端A:

圖片

B更新數據:

客戶端B:

圖片

客戶端A:

圖片

通過上面的實驗能夠得出結論,事務B更新了一條記錄,可是沒有提交,此時事務A能夠查詢出未提交記錄。形成髒讀現象。未提交讀是最低的隔離級別。

(二)、將客戶端A的事務隔離級別設置爲read committed(已提交讀)

在B未更新數據以前:

客戶端A:

圖片

5.2 事務的其餘知識點:

事務併發執行的好處:提升吞吐量和資源利用率、減小等待時間。

事務調度的分類:可恢復調度、無級聯調度。

併發控制依賴的技術手段:鎖、時間戳、多版本和快照隔離

鎖:讀鎖(共享鎖)、寫鎖(獨佔鎖、排查鎖)

鎖粒度:從大到小,Mysql服務器只支持表級鎖,行鎖須要有存儲引擎完成;


5.3 事務的控制命令:

START TANSACTION:啓動
SQL語句
……

ROLLBACK: 回滾
COMMIT: 提交

事務流程以下:

<a href="http://www.toxingwang.com/wp-content/uploads/2013/09/mysql.jpg" class="cboxElement" rel="example4" 1454"="" style="text-decoration: none; color: rgb(1, 150, 227);">圖片

須要注意的是,事務的回滾須要在提交以前,若是已經提交了,就沒法回滾了。

另外在Mysql下,若是沒有明確啓動事務,且autocommit變量設置爲1,就會實現自動提交,每個操做都直接提交

查看當前autocommit設置:

mysql> SELECT @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.01 sec)

在MySQL的InnoDB存儲引擎下,爲了保障數據的持久性,默認將autocommit置爲1,以實現自動提交事務。但爲了數據的安全性,建議明確使用事務


5.4 事務的保存點:

在一個事務中,若是包含的語句較多,如一個事務要執行100條SQL語句,若是執行到99條的時候,發現95條出現了錯誤,須要回退,莫非只能所有回滾?

爲了防止這樣的狀況發生,引入了保存點(SAVEPOINT)的概念。加入仍是上述的100條語句,若是每十條語句創建一個保存點,那麼則只需回滾至第90條便可,極大的提升了效率。

具體命令和流程以下:

START TANSACTION:啓動
SQL
……

SAVEPOINT sid_one :建立保存點
SQL

……

SAVEPOINT sid_two :建立保存點

……

ROLLBACK TO sid :回滾到指定保存點 COMMIT: 提交

相關文章
相關標籤/搜索