概述

最近因為工作需要,對MySQL的事務處理進行了一系列測試驗證,其中,對于MySQL的事務到底時什么時候生成了數據的快照,結果似乎跟薛定諤的貓理念很像,很有意思;過程我貼出來,有興趣的朋友可以一起研究研究。

事務不依賴于虛擬表或者輔助表,而是主要依賴于 MySQL 的 InnoDB 存儲引擎所提供的多版本并發控制 (MVCC) 機制和事務日志。

在事務開始時,MySQL 會記錄當前事務的快照 (snapshot),這意味著在事務期間,你看到的數據是事務開始時的版本,即使其他事務對數據進行了修改。

本文的所有步驟嚴格按照時間線前后關聯,順序變了,結果就會變化。

【MySQL】事務的快照生成時間點和薛定諤的貓相關?_事務

假如有如下表:

# 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.

這再次印證了;只要在事務開始后以任何形式觀察過數據,那么從這一刻開始新的分支就形成了;真的很像薛定諤的貓和平行宇宙的感覺。