ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

同一个表名,两个连接查到不同数据?MySQL临时表到底跟谁走

同一个表名,两个连接查到不同数据?MySQL临时表到底跟谁走

两个 MySQL 窗口,都连着同一个实例、同一个库,执行的也是同一句查询:

SELECT label FROM blog_scope_item; 窗口A:temporary-A 窗口B:permanent

先不往“隔离级别”上猜。这个例子里没有未提交的数据,也不需要构造快照差异。窗口 A 比 B 多做了一件事:创建了一张同名临时表。

旧的 InnoDB 提纲里,临时表、临时表空间和内部临时表放在一起,容易记成一串名字。这次先只看我们自己用CREATE TEMPORARY TABLE创建的表,搞清楚它属于哪个连接、什么时候消失。

先让两个窗口看到同一张普通表

下面在独立测试实例里做,不要用业务库。新建的库名如果已经存在,就换一个名字,并同步改后面的USE,不要删除已有库来照抄实验。

本次实际环境是 MySQL 8.0.46,新建 A、B 两个持续连接,均使用默认的autocommit=1。每一小段按标注的连接执行,不要把 SQL 工具的两个编辑页签直接当作两个连接;可以先用SELECT CONNECTION_ID()核对它们是否不同。

在 A 创建专用实验库和一张普通表:

CREATE DATABASE blog_temp_scope_lab; USE blog_temp_scope_lab; CREATE TABLE blog_scope_item ( id INT PRIMARY KEY, label VARCHAR(32) NOT NULL ) ENGINE=InnoDB; INSERT INTO blog_scope_item VALUES (1, 'permanent'); SELECT label FROM blog_scope_item;

输出permanent。

B 也选中这个库:

USE blog_temp_scope_lab; SELECT label FROM blog_scope_item;

同样是permanent。目前两个连接访问的是同一张普通表。

A建一张同名临时表,普通表被覆盖了吗?

在 A 执行:

CREATE TEMPORARY TABLE blog_scope_item ( id INT PRIMARY KEY, label VARCHAR(32) NOT NULL ) ENGINE=InnoDB; INSERT INTO blog_scope_item VALUES (1, 'temporary-A'); SELECT label FROM blog_scope_item;

这次得到temporary-A。

注意,这里没有清空普通表,也没有用新数据更新它。MySQL 允许临时表与同库中的普通表同名;对 A 而言,后续这个名字先解析到它自己的临时表。

连接A查blog_scope_item | v A的同名临时表 temporary-A 普通表permanent仍在 只是这个名字在A中先指向了临时表

现在去 B 查:

SELECT label FROM blog_scope_item;

它仍然得到permanent。

所以不是普通表的数据被改了,也不是 A 的临时数据尚未提交给 B。这张临时表只对创建它的会话可见。A、B 用同一个名字,最终指向的对象可以不同。MySQL 临时表说明

B也建一张同名临时表呢?

既然 A 的临时表对 B 不可见,B 也可以使用这个名字:

CREATE TEMPORARY TABLE blog_scope_item ( id INT PRIMARY KEY, label VARCHAR(32) NOT NULL ) ENGINE=InnoDB; INSERT INTO blog_scope_item VALUES (1, 'temporary-B'); SELECT label FROM blog_scope_item;

得到temporary-B。这时再在 A 查询:

SELECT label FROM blog_scope_item;

仍然是temporary-A。同一个库名、同一个表名,现在实际上对应三份对象:

A自己的临时表 -> temporary-A B自己的临时表 -> temporary-B 普通表 -> permanent A查名字 -> A的临时表 B查名字 -> B的临时表

如果只拿着库名、表名比对,两个人都可能觉得“我查的肯定就是你那张”。这里还得看会话。

删掉临时表后,为什么原来的数据又出现了?

在 A 明确删除临时表,再查同一个名字:

DROP TEMPORARY TABLE blog_scope_item; SELECT label FROM blog_scope_item;

结果变回permanent。

它不是从回收站“恢复”了,也没有把临时表回滚成旧版本。普通表一直在那里,只是挡在前面的同名临时表被移走了:

删除前:A查名字 -> 临时表 删除后:A查名字 -> 普通表 普通表本身没有被改动

B 那边又怎样?

SELECT label FROM blog_scope_item;

还是temporary-B。A 只能删掉自己会话里的那一张,B 的临时表不受影响。

这里特意写DROP TEMPORARY TABLE,不是随手用DROP TABLE。前者把意图限制到临时表;在有同名普通表时,这个区分很重要,不能把“不存在时再试一次删除”当成无害操作。

临时表是跟事务走,还是跟连接走?

还有一个容易想当然的地方:既然叫临时表,事务结束就该没了吧?

换一个不与普通表重名的名字,在 A 做下面这组操作:

START TRANSACTION; CREATE TEMPORARY TABLE blog_tx_temp ( id INT PRIMARY KEY ) ENGINE=InnoDB; INSERT INTO blog_tx_temp VALUES (1); ROLLBACK; SELECT COUNT(*) FROM blog_tx_temp;

结果不是“表不存在”,而是0。

这里发生了两件需要分开看的事:

创建临时表 -> 表存在 插入一行 -> 表里有1行 ROLLBACK -> 插入回滚,剩0行 临时表本身仍在

本例使用 InnoDB,所以这次插入的数据可以回滚。CREATE TEMPORARY TABLE本身不因ROLLBACK被撤销;它也不像许多普通 DDL 那样隐式提交当前事务。不要把“没有隐式提交”和“这个DDL能回滚”混成一件事。MySQL 隐式提交说明

继续在同一个 A 连接里插入、查询:

INSERT INTO blog_tx_temp VALUES (2); SELECT id FROM blog_tx_temp; DROP TEMPORARY TABLE blog_tx_temp;

能查到2。这也再次说明,前一次事务结束,没有结束这张临时表的生命周期。

真正结束连接,才是另一回事

现在让 B 断开,再建立一个新的连接 C,选中同一个库,执行:

USE blog_temp_scope_lab; SELECT label FROM blog_scope_item;

会得到permanent。B 的临时表在原会话结束后自动删除,新连接没有继承它。

这不是让 C 去访问 B 的私有表;C 解析这个名字时,没有自己的临时表,就访问普通表。实验中还另外核对了 B 的会话确实已经结束,而不是只关了一个编辑页签。

这对连接池也有影响。业务代码调用“关闭”,可能只是把连接归还池里,没有结束 MySQL 的物理会话。若驱动或连接池没有做会话重置、清理,临时表就不能仅凭“这次请求结束了”被认定已消失。这里具体要核对连接池的重置策略,不能说所有池都会泄漏,也不能说所有池都会自动替你清理。

用完后在 B 断开前主动删除自己创建的临时表,或者在应用里明确安排清理,比依靠它名字里那个“临时”更可靠。清理对象也应是自己建立的实验表,不要对未知同名表盲删。

我们这次说的,不是所有“临时表”

以上全部是显式CREATE TEMPORARY TABLE创建的表。优化器为了排序、聚合等操作建立的内部临时表,是另一个话题,不能把它们的创建方式、可见性和控制参数直接套过来。

同样,“临时表”不等于“数据永远只在内存”。本例明确指定了 InnoDB,不能拿它当 MEMORY 引擎的实验,更没有通过前面的查询验证数据文件的具体布局。这次先把会话作用域、同名遮蔽、事务回滚三件事讲清。

这组SQL怎么验证

我用独立数据目录启动 MySQL 8.0.46,只通过本地套接字访问,不连接业务数据库。程序保持 A、B 两个客户端进程,按正文顺序,把每一段 SQL 发到对应连接,再逐段核对输出。

到“断开 B”时,程序真正结束 B 的客户端,再创建 C;不是在同一个连接里换个变量名。还用原 B 的连接编号检查它已经不在进程列表中,之后才检查 C 的结果。

对于回滚那一节,另外补了一个对照:在普通实验表中先更新,再创建临时表,然后回滚,确认普通表的更新也撤销了。这是在检查“临时表DDL没有偷偷提交前面的更新”,而不只是发现临时表还存在,就推断事务如何处理。

最后,这些用例不能证明某个真实项目里的连接池一定怎样工作;它们给出的,是你检查自己项目时可以分开观察的状态和动作。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进