MYSQL標準定義了4種隔離級別,用來限定事務內外的哪些改變是可見的,哪些是不可見的。
低的隔離級一般支持更高的併發處理,並擁有更低的系統開銷。
隔離級別由低到高:Read Uncommitted < Read Committed < Repeatable Read < Serializable.
第一:READ UNCOMMITTED (讀取未提交內容)
在該隔離級別,所有事務都可以看到其他未提交(commit)事務的執行結果。
本隔離級別很少用於實際應用,因爲它的性能也不比其他級別好多少。
讀取未提交的數據,也被稱爲髒讀(Dirty Read).
[窗口A]:
mysql> set GLOBAL tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)
mysql> use test;
Database changed
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
[窗口B]:
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test.user values (3, 'c');
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.00 sec)
//目前爲止,窗口B並未commit;
[窗口A]:
mysql> select * from user ;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.00 sec)
第二:READ COMMITTED (讀取提交內容)
這是大多數數據庫的默認隔離級別(但不是MYSQL默認的)。
它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。
這種隔離級別也支持所謂的不可重得讀(NonrepeatableRead),因爲同一事務的其他實例在該實例處理
其間可能會有新的COMMIT,所以同一SELECT 可能返回不同結果。
[窗口A]:
mysql> SET GLOBAL tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
[窗口B]:
mysql> SELECT @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
mysql> delete from test.user where id=1;
Query OK, 1 row affected (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
+----+------+
1 row in set (0.00 sec)
[窗口A]:
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
[窗口B]:
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
[窗口A]:
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
+----+------+
1 row in set (0.00 sec)
第三:Repeatable Read(可重讀)
這是MYSQL的默認事務隔離級別,它確保同一事務的多個實例在併發讀取數據時,會看到同樣的數據行。
不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。
簡單的說,幻讀指當用戶讀取某一範圍的數據行時,另一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的“幻影”行。
INNODB和Falcon存儲引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)
機制解決了該問題。
[窗口A]:
mysql> SET GLOBAL tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
[窗口B]:
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> insert into test.user values (4, 'd');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
| 4 | d |
+----+------+
2 rows in set (0.00 sec)
[窗口A]:
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
+----+------+
1 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
| 4 | d |
+----+------+
2 rows in set (0.00 sec)
第四:Serializable(序列化執行)
這是最高的隔離級別,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。
簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
[窗口A]:
mysql> SET GLOBAL tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set (0.00 sec)
mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
| 4 | d |
+----+------+
2 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test.user values (5, 'e');
Query OK, 1 row affected (0.00 sec)
[窗口B]:
mysql> quit;
Bye
[root@vagrant-centos65 ~]# mysql -uroot -pxxxx(重新登錄)
mysql> SELECT @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set (0.00 sec)
mysql> select * from test.user;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
[窗口A]:
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
[窗口B]:
mysql> mysql> select * from test.user;
+----+------+
| id | name |
+----+------+
| 2 | b |
| 4 | d |
| 5 | e |
+----+------+
3 rows in set (0.00 sec)