MySQL之事務隔離級別案例理解

一、事務的ACID特性

正如我們所知,事務有着ACID四個特性,分別爲:
1. 原子性(atomicity)
一個事務被視爲是一個不可分割的最小工作單元,事務中的語句,要麼全部提交成功,要麼全部失敗回滾。
2. 一致性(consistency)
數據庫總是從一個一致性狀態轉換成另外一個一致性的狀態。事務沒有提交,事務中做出的修改就不會保存到數據庫中。
3. 隔離性(isolation)
通常在一個事務所做的修改在最終提交之前,對其它事務不可見。
4. 持久性(durability)
事務一旦提交,其做出的修改會保存到數據庫中,即使系統崩潰,修改的數據也不會丟失。


二、隔離級別

隔離級別規定了一個事務中所做的修改,在其他事務內、事務間的可見性。

設置事務隔離級別(:修改global事務隔離級別,重新登陸數據庫才能生效。)

set global tx_isolation='REPEATABLE-READ'
set session tx_isolation='REPEATABLE-READ'

查詢事務隔離級別

select @@tx_isolation;
select @@global.tx_isolation;
select @@session.tx_isolation;

不同的數據庫產品默認的事務隔離級別是不同的,大多數系統的默認級別爲提交讀(RC),MySQL的默認級別爲可重複讀(RR)。

1. 未提交讀(Read Uncommitted)

未提交讀:事務中的修改,即使沒有提交,對於其他事務也都是可見的。

事務讀取到未提交的數據,即爲髒讀(dirty read)。

案例分析

(1)首先準備數據

use test;
create table test(
    id int(5) not null
) engine=innodb default charset=utf8;
insert test(id) values(100),(200),(300),(400);

(2)設置數據庫的隔離級別爲RU。

mysql> set global tx_isolation='READ-UNCOMMITTED';
mysql> select @@tx_isolation;
Name          |Value           |
--------------|----------------|
@@tx_isolation|READ-UNCOMMITTED|

(3)事務操作

session A操作–開始事務

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

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
+-----+
4 rows in set (0.00 sec)

session B操作–開始事務,並修改

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

mysql> insert into test values(500);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
| 500 |
+-----+
5 rows in set (0.00 sec)

session A操作

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
| 500 |
+-----+
5 rows in set (0.00 sec)

從上面的案例中,session B並沒有對事務進行提交(commit),session A依然可以看到新的記錄。

2. 提交讀(Read Committed)

提交讀:事務從開始到提交之前,其做出的修改對於其他事務不可見。

克服了髒讀,但是無法避免不可重複讀和幻讀。

不可重複讀,即兩次執行同樣的查詢,得到的結果可能不一致。

案例分析
(1)設置數據庫隔離級別爲RC

mysql> set global tx_isolation='READ-COMMITTED';
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+

(2)事務操作

session A操作–開始事務

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

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
+-----+
4 rows in set (0.00 sec)

session B操作–開始事務

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

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
+-----+
4 rows in set (0.00 sec)

mysql> update test set id=999 where id=600;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 600 |
+-----+
4 rows in set (0.00 sec)

session A操作

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
+-----+
4 rows in set (0.09 sec)

session B操作–提交事務

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

session A操作

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 600 |
+-----+
4 rows in set (0.00 sec)

案例中,session B事務未提交之前,session A看不到B的修改。提交之後,可以讀取到。

3. 可重複讀(Repeatable Read)

可重複讀可以保證同一個事務中多次讀取同樣記錄的結果是一致的。

克服了髒讀和不可重複讀,可能出現幻讀。(MVCC解決了部分幻讀問題)

幻讀,即當某個事務在讀取某個範圍記錄時,其他事務又在範圍內插入了新的數據,當前之前的事務再次讀取該範圍記錄時,產生幻行。

案例分析
(1)設置事務隔離級別

mysql> set global tx_isolation='REPEATABLE-READ';
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

(2)事務操作

session A操作–開始事務

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

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
| 500 |
+-----+
5 rows in set (0.00 sec)

session B操作–修改並提交事務

mysql> insert into test values(600);
Query OK, 1 row affected (0.36 sec)

session A操作

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
| 500 |
+-----+
5 rows in set (0.00 sec)

session A操作–提交事務

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

mysql> select * from test;
+-----+
| id  |
+-----+
| 100 |
| 200 |
| 300 |
| 400 |
| 500 |
| 600 |
+-----+
6 rows in set (0.00 sec)

小結:可重複讀級別只能讀取已經提交的數據,並且在一個事務中,讀取事務開始時的數據。

彙總

隔離級別 髒讀 不可重複讀 幻讀 加鎖讀
未提交讀
提交讀
可重複讀
可序列化

4. 可序列化(Serializable)

最高的隔離級別。在讀取的每一行數據上加鎖,強制事務串行執行,使之不可能衝突,從而解決幻讀問題。因此,會導致大量的超時和鎖爭用,不利於併發。


三、不可重複讀和幻讀的個人理解

  • 髒讀–針對未提交的數據。

  • 不可重複讀–針對事務內多次讀取數據,數據本身的對比(側重update)。

  • 幻讀–針對事務內多次讀取同一範圍的數據,數據條數的對比(側重insert、delete)。

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