是否可以回滚主要 SQL 数据库中的 CREATE TABLE 和 ALTER TABLE 语句?

Posted

技术标签:

【中文标题】是否可以回滚主要 SQL 数据库中的 CREATE TABLE 和 ALTER TABLE 语句?【英文标题】:Is it possible to roll back CREATE TABLE and ALTER TABLE statements in major SQL databases? 【发布时间】:2011-06-09 05:25:27 【问题描述】:

我正在开发一个发布 DDL 的程序。我想知道CREATE TABLE和类似的DDL是否可以回滚

Postgres mysql SQLite 等

描述每个数据库如何使用 DDL 处理事务。

【问题讨论】:

根据this,H2 也不支持大多数 SQL 命令的事务性 DDL 语句。 【参考方案1】:

看起来其他答案已经过时了。

截至 2019 年:

Postgres 在许多版本中都支持事务 DDL。 SQLite 在许多版本中都支持事务 DDL。 MySQL 已支持Atomic DDL since 8.0(2018 年发布)。

【讨论】:

需要注意的是,MySQL 8 中的 Atomic DDL 仅指原子 DDL 语句,而不是事务语句。一个 DDL 语句,无论是否是原子的,大多数情况下仍然会导致隐式提交,因此不能在另一个事务中执行(例如START TRANSACTION ... COMMIT;。因此,如果同一事务中的后一个语句失败,您仍然无法回滚事务中的 DDL 语句。(见注释在dev.mysql.com/doc/refman/8.0/en/…)【参考方案2】:

不能用 MySQL 完成,看起来很愚蠢,但确实如此......(根据公认的答案)

"InnoDB 中的 CREATE TABLE 语句作为单个处理 交易。这意味着来自用户的 ROLLBACK 不会撤消 用户在该事务期间所做的 CREATE TABLE 语句。”

https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html

尝试了几种不同的方法,它根本不会回滚..

解决方法是简单地设置一个失败标志并在其中一个查询失败时执行“drop table tblname”..

【讨论】:

该死的。我一直试图弄清楚为什么在过去一个小时内某个特定(创建)表失败时以前创建的表不会消失。我正在使用 MariaDB(XAMPP 从 MySQL 切换到 MariaDB),但情况是一样的。这很愚蠢:| 不幸的是,从 v10.5 开始,MariaDB 仍然不支持事务 DDL,详情请参阅this。【参考方案3】:

http://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis 从 PostgreSQL 的角度概述了这个问题。

根据本文档,DDL 是事务性的吗?

PostgreSQL - 是的 MySQL - 否; DDL 导致隐式提交 Oracle 数据库 11g 第 2 版及更高版本 - 默认情况下不支持,但存在称为基于版本的重新定义的替代方法 旧版本的 Oracle - 否; DDL 导致隐式提交 SQL Server - 是的 Sybase Adaptive Server - 是 DB2 - 是的 Informix - 是的 Firebird (Interbase) - 是的

SQLite 似乎也有事务性 DDL。我能够在 SQLite 中 ROLLBACK CREATE TABLE 声明。它的CREATE TABLE 文档没有提到任何特殊的事务性“陷阱”。

【讨论】:

然而,sqlite 的默认 Python 驱动程序阻止了事务性 SQL。 bugs.python.org/issue10740 所以答案是“是的,它们可以回滚,除非您使用的是 MySQL 或旧版本的 Oracle。” 不,除了列出的SQL数据库之外,还有其他SQL数据库。 MariaDB 中存在一个用于添加事务 DDL 支持的未解决问题:jira.mariadb.org/browse/MDEV-4259。请为它投票。 SQLite 有限的ALTER TABLE 语句也可以回滚。 documentation 中没有明确提及。这里提到的是如何在事务中执行“高级”更改。【参考方案4】:

PostgreSQL 为大多数数据库对象(当然是表、索引等,但不包括数据库、用户)提供事务 DDL。然而,实际上任何 DDL 都会在目标对象上获得ACCESS EXCLUSIVE 锁定,使其在 DDL 事务完成之前完全无法访问。此外,并非所有情况都得到了很好的处理——例如,如果您尝试从表 foo 中进行选择,而另一个事务正在删除它并创建替换表 foo,那么被阻止的事务最终将收到一个错误,而不是找到新的foo 表。 (编辑:这是在 PostgreSQL 9.3 或之前修复的)

CREATE INDEX ... CONCURRENTLY 是个例外,它使用三个事务向表添加索引同时允许并发更新,因此它本身不能在事务中执行。

另外,数据库维护命令VACUUM不能在事务中使用。

【讨论】:

我认为,如果我尝试从表 foo 中进行选择,而另一个事务正在删除并重新创建它,那么我可以接受旧版本或错误。我对新版本不满意,因为它还没有提交,所以我一定看不到它。我可以接受错误,因为在并发事务访问中,无论如何都必须准备好重新启动事务。如果错误发生的频率超出了必要,它可能会降低性能,但它仍然是正确的。 @JanHudec:您不会看到新表的未提交版本,只会看到删除/重新创建它的整个事务的结果。即删除、重新创建和重新填充表的事务对于从该表中选择的其他进程来说实际上是原子的。 (但是一旦他们尝试读取表的架构,一切都会被阻止)【参考方案5】:

虽然严格来说它不是“回滚”,但在 Oracle 中,FLASHBACK 命令可用于撤消这些类型的更改,前提是数据库已配置为支持它。

【讨论】:

以上是关于是否可以回滚主要 SQL 数据库中的 CREATE TABLE 和 ALTER TABLE 语句?的主要内容,如果未能解决你的问题,请参考以下文章

java中jdbc多表操作如何事物回滚

php mysql commit之后还可以rollback么

如何从事务日志执行 SQL 回滚

SQL:清理数据库,检查没有违规并可能回滚

sql 事务自动回滚

是否可以在 db2 中的 create table 语句本身中定义索引?