MySQL 4 種隔離級別的區別

## 測試環境
mysql> select version();
+------------+
| version()  |
+------------+
| 5.7.11-log |
+------------+

數據庫事務特性 ACID,即html

A(Atomicity)   -原子性mysql

C(Consistency)- 一致性sql

I(Isolation)     - 隔離性數據庫

D(Durability)   - 持久性session

MySQL 提供了 4 種不一樣的隔離級別,用來支持多版本併發控制(MVCC,Multi-Version Concurrency Control)。併發

默認的事務隔離級別是 REPEATABLE-READ(可重讀):測試

mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-------------------------+---------------------------+
| @@global.tx_isolation   | @@session.tx_isolation    |
+-------------------------+---------------------------+
| REPEATABLE-READ         | REPEATABLE-READ           |
+-------------------------+---------------------------+

在該事務級別下,一個事務期間內,該事務不考慮其餘提交語句。spa

 

0x00、測試準備

1. 建立測試表rest

mysql> CREATE TABLE `transaction_test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `val` varchar(20) NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

 

2. 開啓兩個 MySQL 客戶端進行測試code

 

0x0一、REPEATABLE-READ(可重讀)

step 1:

在 Client 1 下開啓事務,查詢測試表中的數據:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from transaction_test;
Empty set (0.00 sec)

 

step 2:

在 Client 2 下開啓事務,而且往測試表中插入數據,但不提交事務:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:20:59 |
|  2 | y   | 2017-02-06 00:20:59 |
|  3 | z   | 2017-02-06 00:20:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

 

step 3:

在 Client 1 下查看錶中數據:

mysql> select * from transaction_test;
Empty set (0.00 sec)

仍然是空表。

 

step 4:

Client 2 提交事務:

mysql> commit;
Query OK, 0 rows affected (0.12 sec)

 

step 5:

Client 1 下查看錶中數據:

mysql> select * from transaction_test;
Empty set (0.00 sec)

任然是空表。

 

step 6:

Client 1 提交事務,查看錶中數據:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:20:59 |
|  2 | y   | 2017-02-06 00:20:59 |
|  3 | z   | 2017-02-06 00:20:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

當 Client 1 完成事務後,才能看到其餘事務提交的數據。

 

0x0二、READ-COMMITTED(讀取提交內容)

step 1:

Client 1 中清空表,改變數據庫隔離級別:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.10 sec)

mysql> set @@session.tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ       | READ-COMMITTED         |
+-----------------------+------------------------+
1 row in set (0.00 sec)

 

step 2:

Client 1 開啓事務,查詢表中數據:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from transaction_test;
Empty set (0.00 sec)

 

step 3:

Client 2 開啓事務,向表中插入數據,但不提交事務:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:31:00 |
|  2 | y   | 2017-02-06 00:31:00 |
|  3 | z   | 2017-02-06 00:31:00 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

 

step 4:

Client 1 下查看錶中數據:

mysql> select * from transaction_test;
Empty set (0.00 sec)

仍然是空表。

 

step 5:

Client 2 提交事務:

mysql> commit;
Query OK, 0 rows affected (0.13 sec)

 

step 6:

Client 1 下查看錶中數據:

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:31:00 |
|  2 | y   | 2017-02-06 00:31:00 |
|  3 | z   | 2017-02-06 00:31:00 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

與 REPEATABLE-READ 不一樣的是,Client 1 沒有結束事務也能看到其餘事務提交的數據。

 

0x0三、READ-UNCOMMITTED(讀取未提交內容)

step 1:

Client 1 下清空表,設置隔離級別:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.10 sec)

mysql> set @@session.tx_isolation = 'READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ       | READ-UNCOMMITTED       |
+-----------------------+------------------------+
1 row in set (0.00 sec)

 

step 2:

Client 1 下開啓事務,查詢表數據:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from transaction_test;
Empty set (0.00 sec)

 

step 3:

Client 2 下開啓事務,向表中插入數據,可是不提交事務:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:43:59 |
|  2 | y   | 2017-02-06 00:43:59 |
|  3 | z   | 2017-02-06 00:43:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

 

step 4:

Client 1 中查詢數據:

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  1 | x   | 2017-02-06 00:43:59 |
|  2 | y   | 2017-02-06 00:43:59 |
|  3 | z   | 2017-02-06 00:43:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

與 READ-COMMITTED 不一樣的是,在 Client 2 不提交事務的狀況下,Client 1 也能讀到其餘事務插入的數據,即髒數據或者說產生了「髒讀」。在一個事務期間讀到了另外一個事務在未提交以前產生的數據,那麼第一個事務就讀到了髒數據,產生了對第二個事務未提交數據的依賴,若是第二個事務回滾,那麼第一個事務讀到的數據是錯誤的髒數據。

「髒讀」與「幻讀」、「不可重複讀」的區別是:幻讀是讀取結果集條數的對比,一個事務按相同的查詢條件查詢以前檢索過的數據,發現檢索出來的結果集條數變多或者減小(由其餘事務插入、刪除的),相似產生幻覺。

不可重複讀是讀取的數據自己的對比,一個事務在讀取某些數據後的一段時間後,再次讀取這個數據,發現其讀取出來的數據內容已經發生了改變,就是不可重複讀。

 

step 5:

Client 2 回滾事務:

mysql> rollback;
Query OK, 0 rows affected (0.04 sec)

mysql> select * from transaction_test;
Empty set (0.00 sec)

 

step 6:

Client 1 查詢表數據:

mysql> select * from transaction_test;
Empty set (0.00 sec)

空表。

 

0x0四、SERIALIZABLE(序列化)

step 1:

Client 1 下清空表,設置隔離級別:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.21 sec)

mysql> set @@session.tx_isolation ='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ       | SERIALIZABLE           |
+-----------------------+------------------------+
1 row in set (0.00 sec)

 

step 2:

Client 1 開啓事務,查詢表:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from transaction_test;
Empty set (0.00 sec)

 

step 3:

Client 2 開啓事務,向表中插入數據:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

此時 Client 2 插入數據(INSERT 操做)會被阻塞,直到第一個(Client 1)事務提交後,Client 2 的插入操做才能完成。

 

step 4:

Client 1 提交事務:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

 

step 5:

Client 2 插入數據:

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created             |
+----+-----+---------------------+
|  4 | x   | 2017-02-06 00:54:17 |
|  5 | y   | 2017-02-06 00:54:17 |
|  6 | z   | 2017-02-06 00:54:17 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

 

參考:

[MySQL]對於事務併發處理帶來的問題,髒讀、不可重複讀、幻讀的理解

相關文章
相關標籤/搜索