【MySQL】事务的快照生成时间点和薛定谔的猫相关?

概述

最近因为工作需要,对MySQL的事务处理进行了一系列测试验证,其中,对于MySQL的事务到底时什么时候生成了数据的快照,结果似乎跟薛定谔的猫理念很像,很有意思;过程我贴出来,有兴趣的朋友可以一起研究研究。

事务不依赖于虚拟表或者辅助表,而是主要依赖于 MySQL 的 InnoDB 存储引擎所提供的多版本并发控制 (MVCC) 机制和事务日志。

在事务开始时,MySQL 会记录当前事务的快照 (snapshot),这意味着在事务期间,你看到的数据是事务开始时的版本,即使其他事务对数据进行了修改。

本文的所有步骤严格按照时间线前后关联,顺序变了,结果就会变化。

假如有如下表:
登录后复制

plain 复制代码
# Session 2
 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.0005 sec)
 MySQL  localhost:3306 ssl  xiaml  SQL >

测试1:事务中进行了数据观察

登录后复制

plain 复制代码
# Session1
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql>  
-- 此时并不建立快照,此时对事务而言,数据与实际表完全一致。5行数据。但是别查询!!

登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# 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;后的任何语句就是精确的快照点。

登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# 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:事务中先不做数据观察

那我们再做个实验;事务开始后不做任何地数据的操作甚至查询都不做,只定义一个变量;然后在另一个会话删除数据然后观察删除是否在事务中产生分支?
登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# Sesson2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> 
-- 此时并不建立快照,此时对事务而言,数据与实际表完全一致。5行数据。但是别查询!!
-- 在另一个会话中删除2条数据

登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# 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条数据

登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# 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条数据

登录后复制

plain 复制代码
# 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 >

登录后复制

plain 复制代码
# 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>
-- 因为快照已建立,因此,对于事务来说时间就凝固在那一刻了;其他会话的改变对凝固状态下的数据无影响。

这再次印证了;只要在事务开始后以任何形式观察过数据,那么从这一刻开始新的分支就形成了;真的很像薛定谔的猫和平行宇宙的感觉。

相关推荐
ClouGence1 天前
Oracle CDC 架构优化:从主库直连到 DataGuard 备库同步
数据库·后端·oracle
云技纵横1 天前
Gap Lock 死锁实战:5 秒在本地复现 MySQL 间隙锁死锁
后端·mysql
无响应de神1 天前
三、用户与权限管理
数据库·mysql
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
麦聪聊数据2 天前
数据服务化时代:企业数据能力输出的核心路径
数据库
ApacheSeaTunnel2 天前
实战演示 | 基于 Apache SeaTunnel 与 Apache DolphinScheduler 实现 MySQL 到 Doris 离线定时增量同步
大数据·mysql·开源·doris·数据集成·seatunnel·数据同步
shushangyun_2 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
DARLING Zero two♡2 天前
【MySQL数据库】数据类型与表约束
数据库·mysql
曹牧2 天前
Oracle EXPLAIN PLAN
数据库·oracle