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

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

相关推荐
陈平安安16 分钟前
设计一个秒杀功能
java·数据库·sql
isNotNullX23 分钟前
数据处理的流程是什么?如何进行数据预处理?
数据库·数据资产管理·数据处理·企业数字化
TAEHENGV26 分钟前
基本设置模块 Cordova 与 OpenHarmony 混合开发实战
android·java·数据库
Leo18730 分钟前
MySQL 回表(Back to Table)详解
数据库·mysql
遇见火星33 分钟前
MySQL 8.0复制架构主从自动切换脚本
mysql·adb·架构·mysql8.0·mysql主从
不知江月待何人..34 分钟前
MySQL服务无法启动问题
数据库·mysql
廋到被风吹走40 分钟前
【数据库】【Oracle】SQL基础
数据库·sql·oracle
曹牧1 小时前
Oracle统计每日发生次数
数据库·oracle
范纹杉想快点毕业1 小时前
返璞归真还是拥抱现代?——嵌入式研发中的“裸机开发”与RTOS全景解析
c语言·数据库·mongodb·设计模式·nosql
辗转.9531 小时前
MongoDB入门指南:从零开始掌握NoSQL数据库
数据库·mongodb·nosql