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

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

相关推荐
陈丹阳(滁州学院)20 分钟前
若依添加添加监听容器配置(删除键,键过期)
数据库·oracle
远方16091 小时前
14-Oracle 23ai Vector Search 向量索引和混合索引-实操
数据库·ai·oracle
GUIQU.2 小时前
【Oracle】数据仓库
数据库·oracle
恰薯条的屑海鸥3 小时前
零基础在实践中学习网络安全-皮卡丘靶场(第十六期-SSRF模块)
数据库·学习·安全·web安全·渗透测试·网络安全学习
咖啡啡不加糖3 小时前
Redis大key产生、排查与优化实践
java·数据库·redis·后端·缓存
曼汐 .3 小时前
数据库管理与高可用-MySQL高可用
数据库·mysql
MickeyCV3 小时前
使用Docker部署MySQL&Redis容器与常见命令
redis·mysql·docker·容器·wsl·镜像
2301_793102493 小时前
Linux——MySql数据库
linux·数据库
喵叔哟3 小时前
第4章:Cypher查询语言基础
数据库
刘 大 望3 小时前
数据库-联合查询(内连接外连接),子查询,合并查询
java·数据库·sql·mysql