概述
最近因為工作需要,對MySQL的事務處理進行了一系列測試驗證,其中,對于MySQL的事務到底時什么時候生成了數據的快照,結果似乎跟薛定諤的貓理念很像,很有意思;過程我貼出來,有興趣的朋友可以一起研究研究。
事務不依賴于虛擬表或者輔助表,而是主要依賴于 MySQL 的 InnoDB 存儲引擎所提供的多版本并發控制 (MVCC) 機制和事務日志。
在事務開始時,MySQL 會記錄當前事務的快照 (snapshot),這意味著在事務期間,你看到的數據是事務開始時的版本,即使其他事務對數據進行了修改。
本文的所有步驟嚴格按照時間線前后關聯,順序變了,結果就會變化。
假如有如下表:
# Session 2MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 7 | 5000.00 |
| 8 | 6000.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
5 rows in set (0.0005 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
測試1:事務中進行了數據觀察
# Session1
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。5行數據。但是別查詢!!
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
# Session 2
# 刪除兩條數據MySQL localhost:3306 ssl xiaml SQL > DELETE FROM accounts WHERE account_id = 7 or account_id = 8;
Query OK, 2 row affected (0.0038 sec)MySQL localhost:3306 ssl xiaml SQL >MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
3 rows in set (0.0009 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
# Session1
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。***********3行數據。**************
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
3 rows in set (0.00 sec)mysql>
-- 此時快照已建立,也就是說START TRANSACTION;后的任何語句就是精確的快照點。
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
# Session 2
# 再刪除一條數據MySQL localhost:3306 ssl xiaml SQL > DELETE FROM accounts WHERE account_id =9;
Query OK, 1 row affected (0.0038 sec)MySQL localhost:3306 ssl xiaml SQL >MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 10 | 2000.00 |
+------------+---------+
2 rows in set (0.0006 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
# Session1
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。***********3行數據。**************
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
3 rows in set (0.00 sec)mysql>
-- 此時快照已建立,也就是說START TRANSACTION;后的任何語句就是精確的快照點。
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
3 rows in set (0.00 sec)mysql>
-- 因為快照已建立,因此,對于事務來說時間就凝固在那一刻了;其他會話的改變對凝固狀態下的數據無影響。
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
很像薛定諤的貓的感覺,只要觀測過,從那一刻就出現了分支。
測試1:事務中先不做數據觀察
那我們再做個實驗;事務開始后不做任何地數據的操作甚至查詢都不做,只定義一個變量;然后在另一個會話刪除數據然后觀察刪除是否在事務中產生分支?
# Session1
MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 7 | 5000.00 |
| 8 | 6000.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
5 rows in set (0.0009 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
# Sesson2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。5行數據。但是別查詢!!
-- 在另一個會話中刪除2條數據
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
# Session1
# 刪除兩條數據MySQL localhost:3306 ssl xiaml SQL > DELETE FROM accounts WHERE account_id =7 or account_id = 8;
Query OK, 2 rows affected (0.0044 sec)MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 9 | 1000.00 |
| 10 | 2000.00 |
+------------+---------+
3 rows in set (0.0015 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
# Session2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。5行數據。但是別查詢!!
-- 在另一個會話中刪除2條數據
mysql> SET @name := 'xiamingliang';
Query OK, 0 rows affected (0.00 sec)mysql>
-- 僅僅在事務中創建一個變量,不對數據進行任何形式的查詢與變更動作!!
-- 在另一個會話中再刪除1條數據
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
# Session1
# 再刪除一條數據MySQL localhost:3306 ssl xiaml SQL > DELETE FROM accounts WHERE account_id = 9;
Query OK, 1 row affected (0.0028 sec)MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 10 | 2000.00 |
+------------+---------+
2 rows in set (0.0005 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
# Session2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。5行數據。但是別查詢!!
-- 在另一個會話中刪除2條數據
mysql> SET @name := 'xiamingliang';
Query OK, 0 rows affected (0.00 sec)mysql>
-- 僅僅在事務中創建一個變量,不對數據進行任何形式的查詢與變更動作!!
-- 在另一個會話中再刪除1條數據
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 10 | 2000.00 |
+------------+---------+
2 rows in set (0.00 sec)mysql>
-- 在另一個會話中再刪除1條數據
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
# Session1
# 再刪除一條數據MySQL localhost:3306 ssl xiaml SQL > DELETE FROM accounts WHERE account_id = 10;
Query OK, 1 row affected (0.0037 sec)MySQL localhost:3306 ssl xiaml SQL > select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
+------------+---------+
1 row in set (0.0013 sec)MySQL localhost:3306 ssl xiaml SQL >
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
# Session2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql>
-- 此時并不建立快照,此時對事務而言,數據與實際表完全一致。5行數據。但是別查詢!!
-- 在另一個會話中刪除2條數據
mysql> SET @name := 'xiamingliang';
Query OK, 0 rows affected (0.00 sec)mysql>
-- 僅僅在事務中創建一個變量,不對數據進行任何形式的查詢與變更動作!!
-- 在另一個會話中再刪除1條數據
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 10 | 2000.00 |
+------------+---------+
2 rows in set (0.00 sec)mysql>
-- 在另一個會話中再刪除1條數據;此時新的快照分支就形成了
mysql> select * from accounts;
+------------+---------+
| account_id | balance |
+------------+---------+
| 4 | 500.00 |
| 10 | 2000.00 |
+------------+---------+
2 rows in set (0.00 sec)mysql>
-- 因為快照已建立,因此,對于事務來說時間就凝固在那一刻了;其他會話的改變對凝固狀態下的數據無影響。
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
這再次印證了;只要在事務開始后以任何形式觀察過數據,那么從這一刻開始新的分支就形成了;真的很像薛定諤的貓和平行宇宙的感覺。