MySQL中事務的ACID及隔離級別的理解


系統環境:
RHEL6.5
MySQL5.5.58

我們知道ACID是衡量一個事物處理系統的標准,下面就ACID做簡要說明,重點討論I(isolation,隔離性)並舉例說明

原子性(Atomicity):一個事務必須被視為一個不可分割的最小工作單元,整個事務中的所有操作要么全部提交成功,要么全部失敗回滾,對於一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性

一致性(Consistency): 數據庫總是從一個一致性的狀態轉換到另一個一致性的狀態。

隔離性(Isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。


持久性(Durability):一旦事務提交,則其所做的修改不會永久保存到數據庫。


在MySQL中隔離性有4種級別,分別是:
read-uncommitted 讀未提交
read-committed 讀提交
repeatable-read 可重讀
serializable 可串行化

打開兩個MySQL終端測試,為了區別,將其中一個提示符修改為--->
建一個cards表,測試4種隔離級別下,事務過程中有可能出現的情況

 1 cards建表語句如下:
 2 mysql> show create table cards \G
 3 *************************** 1. row ***************************
 4        Table: cards
 5 Create Table: CREATE TABLE `cards` (
 6   `id` int(11) NOT NULL AUTO_INCREMENT,
 7   `name` varchar(32) NOT NULL DEFAULT '',
 8   `balance` int(10) unsigned DEFAULT NULL,
 9   PRIMARY KEY (`id`)
10 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
11 1 row in set (0.00 sec)
12 
13 
14 現在表中有一條數據如下所示:
15 mysql> select * from cards;
16 +----+--------------+---------+
17 | id | name         | balance |
18 +----+--------------+---------+
19 |  1 | zhangsanfeng |    5000 |
20 +----+--------------+---------+
21 1 row in set (0.00 sec)
22 
23 
24 查看當前MySQL系統隔離級別
25 mysql> show global variables like '%iso%';
26 +---------------+-----------------+
27 | Variable_name | Value           |
28 +---------------+-----------------+
29 | tx_isolation  | REPEATABLE-READ |
30 +---------------+-----------------+
31 1 row in set (0.00 sec)

改變系統隔離級別,按照上面4中級別依次測試

 1 mysql> set tx_isolation='read-uncommitted';
 2 Query OK, 0 rows affected (0.00 sec)
 3 
 4 關閉自動提交,開啟事務,模擬轉賬,將zhangsanfeng賬戶中的余額減去500
 5 
 6 mysql> set autocommit=0;
 7 Query OK, 0 rows affected (0.00 sec)
 8 mysql> start transaction;
 9 Query OK, 0 rows affected (0.00 sec)
10 mysql> update cards set balance=balance-500 where name='zhangsanfeng';
11 Query OK, 1 row affected (0.00 sec)
12 Rows matched: 1  Changed: 1  Warnings: 0
13 
14 mysql> select * from cards;
15 +----+--------------+---------+
16 | id | name         | balance |
17 +----+--------------+---------+
18 |  1 | zhangsanfeng |    4500 |
19 +----+--------------+---------+
20 1 row in set (0.00 sec)

這時我並沒有提交(commit),現在去第二個終端讀取(這樣主要是模擬現實中並發量很大的情況,這時沒有提交事務,但是有個請求過來讀取)

 1 --->set tx_isolation='read-uncommitted';    #由於是兩個會話終端,終端一中的設置是基於會話的,在終端二中不生效,所以終端二也要設置隔離級別
 2 Query OK, 0 rows affected (0.00 sec)
 3 
 4 --->select * from cards;
 5 +----+--------------+---------+
 6 | id | name         | balance |
 7 +----+--------------+---------+
 8 |  1 | zhangsanfeng |    4500 |
 9 +----+--------------+---------+
10 1 row in set (0.00 sec)
11 
12 --->

可以看到,在終端二中,可以看到終端一提交后的最終結果,但是終端一並沒有提交,所以這種隔離效果最差。
在實際情況中,這樣就容易產生幻讀,就是當一個用戶在讀取數據時,這時別的終端發起了一個事務修改了數據,導致用戶
在前后看到的數據不一致。

同理在read-committed(讀提交)情況下,也會發生幻讀,只是產生幻讀的時間點向后移了,當事務提交后,用戶才會發現
讀取的數據和之前讀取的不同。原理較簡單,就不演示了。

 1 改變系統隔離級別,調整到(repeatable-read)
 2 終端一:
 3 mysql> set tx_isolation='repeatable-read';
 4 Query OK, 0 rows affected (0.00 sec)
 5 
 6 mysql> select * from cards;
 7 +----+--------------+---------+
 8 | id | name         | balance |
 9 +----+--------------+---------+
10 |  1 | zhangsanfeng |    5000 |
11 +----+--------------+---------+
12 1 row in set (0.00 sec)
13 
14 mysql> 
15 
16 終端二:
17 --->set tx_isolation='repeatable-read';
18 Query OK, 0 rows affected (0.00 sec)
19 
20 --->select * from cards;
21 +----+--------------+---------+
22 | id | name         | balance |
23 +----+--------------+---------+
24 |  1 | zhangsanfeng |    5000 |
25 +----+--------------+---------+
26 1 row in set (0.00 sec)
27 
28 --->
29 
30 
31 終端一開啟了一個事務
32 mysql> set autocommit=0;
33 Query OK, 0 rows affected (0.00 sec)
34 
35 mysql> start transaction;
36 Query OK, 0 rows affected (0.00 sec)
37 
38 mysql> update cards set balance=balance-500 where name='zhangsanfeng';
39 Query OK, 1 row affected (0.00 sec)
40 Rows matched: 1  Changed: 1  Warnings: 0
41 
42 mysql> select * from cards;
43 +----+--------------+---------+
44 | id | name         | balance |
45 +----+--------------+---------+
46 |  1 | zhangsanfeng |    4500 |
47 +----+--------------+---------+
48 1 row in set (0.00 sec)
49 
50 mysql> 
51 
52 終端一沒有提交事務,終端二查看結果如下:
53 --->select * from cards;
54 +----+--------------+---------+
55 | id | name         | balance |
56 +----+--------------+---------+
57 |  1 | zhangsanfeng |    5000 |
58 +----+--------------+---------+
59 1 row in set (0.01 sec)
60 
61 --->
62 
63 終端一提交后,終端二在讀取結果如下:
64 mysql> commit;
65 Query OK, 0 rows affected (0.01 sec)
66 
67 mysql> 
68 
69 
70 --->select * from cards;
71 +----+--------------+---------+
72 | id | name         | balance |
73 +----+--------------+---------+
74 |  1 | zhangsanfeng |    4500 |
75 +----+--------------+---------+
76 1 row in set (0.00 sec)
77 
78 --->

這樣雖然也可能產生幻讀,但是產生幻讀的時間點是在另外一個事務結束后,也就是說,事務在未提交之前,其他用戶是感受不到的。
所以相對而言,這種隔離效果較之前兩種要好,起到了事務的隔離效果,又不影響並發,MySQL中默認就是該級別。

 1 接下來測試serializable(串行化)
 2 終端一:
 3 mysql> set tx_isolation='serializable';
 4 Query OK, 0 rows affected (0.00 sec)
 5 
 6 mysql> set autocommit=0;
 7 Query OK, 0 rows affected (0.00 sec)
 8 
 9 mysql> start transaction;
10 Query OK, 0 rows affected (0.01 sec)
11 
12 mysql> update cards set balance=balance-500 where name='zhangsanfeng';
13 Query OK, 1 row affected (0.04 sec)
14 Rows matched: 1  Changed: 1  Warnings: 0
15 
16 mysql> select * from cards;
17 +----+--------------+---------+
18 | id | name         | balance |
19 +----+--------------+---------+
20 |  1 | zhangsanfeng |    4500 |
21 +----+--------------+---------+
22 1 row in set (0.00 sec)
23 
24 mysql> 
25 
26 終端二:
27 --->set tx_isolation='serializable';
28 Query OK, 0 rows affected (0.00 sec)
29 
30 --->select * from cards;
31 +----+--------------+---------+
32 | id | name         | balance |
33 +----+--------------+---------+
34 |  1 | zhangsanfeng |    5000 |
35 +----+--------------+---------+
36 1 row in set (0.00 sec)
37 --->update cards set balance=balance-500 where name='zhangsanfeng';    //這一步可以看到,光標一直卡者,數據的修改不能成功,就是應為上面的事務沒有提交。
38 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可以看到串行化后,當事務沒有結束時,該數據就一直處於鎖定狀態,其他用戶不能操作。這種隔離級別最高,但是不支持並發,
所以在實際情況中一般不會用。

最后總結一下:
事務的隔離級別越高,事務越安全,但是並發能力越差。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM