SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級通常支持更高的併發處理,並擁有更低的系統開銷。
Read Uncommitted(讀取未提交內容)mysql
在該隔離級別,全部事務均可以看到其餘未提交事務的執行結果。本隔離級別不多用於實際應用,由於它的性能也不比其餘級別好多少。讀取未提交的數據,也被稱之爲髒讀(Dirty Read)。
Read Committed(讀取提交內容)web
這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它知足了隔離的簡單定義:一個事務只能看見已經提交事務所作的改變。這種隔離級別 也支持所謂的不可重複讀(Nonrepeatable Read),由於同一事務的其餘實例在該實例處理其間可能會有新的commit,因此同一select可能返回不一樣結果。
Repeatable Read(可重讀)sql
這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在併發讀取數據時,會看到一樣的數據行。不過理論上,這會致使另外一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一範圍的數據行時,另外一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的「幻影」 行。InnoDB和Falcon存儲引擎經過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。數據庫
Serializable(可串行化)
這是最高的隔離級別,它經過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每一個讀的數據行上加上共享鎖。在這個級別,可能致使大量的超時現象和鎖競爭。session
這四種隔離級別採起不一樣的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。例如:併發
髒讀(Drity Read):某個事務已更新一份數據,另外一個事務在此時讀取了同一份數據,因爲某些緣由,前一個RollBack了操做,則後一個事務所讀取的數據就會是不正確的。性能
不可重複讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這多是兩次查詢過程當中間插入了一個事務更新的原有的數據。spa
幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例若有一個事務查詢了幾列(Row)數據,而另外一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。code
mysql修改事務隔離級別orm
用戶能夠用SET TRANSACTION語句改變單個會話或者全部新進鏈接的隔離級別。它的語法以下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
注意:默認的行爲(不帶session和global)是爲下一個(未開始)事務設置隔離級別。若是你使用GLOBAL關鍵字,語句在全局對從那點開始建立的全部新鏈接(除了不存在的鏈接)設置默認事務級別。你須要SUPER權限來作這個。使用SESSION 關鍵字爲未來在當前鏈接上執行的事務設置默認事務級別。 任何客戶端都能自由改變會話隔離級別(甚至在事務的中間),或者爲下一個事務設置隔離級別。
你能夠用下列語句查詢全局和會話事務隔離級別:
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
示例:
Repeatable Read
mysql> describe tb; | |
+-------+-------------+------+-----+---------+-------+ | |
| Field | Type | Null | Key | Default | Extra | | |
+-------+-------------+------+-----+---------+-------+ | |
| id | int(10) | YES | | NULL | | | |
| name | varchar(10) | YES | | NULL | | | |
+-------+-------------+------+-----+---------+-------+ | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
+------+------+ | |
A | B |
mysql> SELECT @@session.tx_isolation; | |
+------------------------+ | |
| @@session.tx_isolation | | |
+------------------------+ | |
| REPEATABLE-READ | | |
+------------------------+ | |
mysql> start transaction; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
+------+------+ | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| REPEATABLE-READ | | |
+-------------------------+ | |
mysql> start transaction; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
+------+------+ | |
mysql> insert into tb (id,name)values('12','323'); | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
+------+------+ | |
mysql> commit; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
+------+------+ | |
mysql> commit; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
READ UNCOMMITTED 讀取未提交內容 | |
mysql> set session transaction isolation level READ UNCOMMITTED; | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| READ-UNCOMMITTED | | |
+-------------------------+ | |
mysql> start transaction; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| REPEATABLE-READ | | |
+-------------------------+ | |
mysql> start transaction; | |
mysql> update tb set name='aaa' where id='1'; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | aaa | | |
| 12 | 323 | | |
+------+------+ | |
mysql> select * from tb;髒讀B還未提交 | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | aaa | | |
| 12 | 323 | | |
+------+------+ | |
mysql> rollback; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> commit; | |
Read Committed(讀取提交內容) | |
mysql> set session transaction isolation level read committed; | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| READ-COMMITTED | | |
+-------------------------+ | |
mysql> start transaction; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> start transaction; | |
mysql> update tb set name='aaa' where id='1'; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | ddd | | |
| 12 | 323 | | |
+------+------+ | |
mysql> commit; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | aaa | | |
| 12 | 323 | | |
+------+------+ | |
mysql> commit; | |
Serializable(可串行化) | |
mysql> set session transaction isolation level serializable; | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| SERIALIZABLE | | |
+-------------------------+ | |
mysql> select @@session. tx_isolation; | |
+-------------------------+ | |
| @@session. tx_isolation | | |
+-------------------------+ | |
| REPEATABLE-READ | | |
+-------------------------+ | |
mysql> start transaction; | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | aaa | | |
| 12 | 323 | | |
+------+------+ | |
mysql> start transaction; | |
mysql> update tb set name='bbb' where id='1'; | |
沒有結果,須要等A事務提交或回滾 | |
mysql> commit; | |
mysql> start transaction; | |
mysql> update tb set name='bbb' where id='1'; | |
這裏成功,沒有鎖tb | |
mysql> select * from tb; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 1 | bbb | | |
| 12 | 323 | | |
+------+------+ | |
mysql> update tb set name='ccccc' where id='1'; | |
又被鎖了,B不在事務狀態下 | |
mysql> commit; | |
mysql> start transaction; | |
mysql> select * from tb where id='12'; | |
+------+------+ | |
| id | name | | |
+------+------+ | |
| 12 | 323 | | |
+------+------+ | |
mysql> update tb set name='ddddd' where id='1'; | |
表被鎖,不是行被鎖 |