mysql 事務的四種隔離級別

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)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章