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


108

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

  • Postgres
  • 的MySQL
  • SQLite的

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


只是为了配合这个线程,H2也并不支持大多数的SQL命令的事务DDL语句,根据这个
加百利·派姆

Answers:


148

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

根据此文档,DDL是否具有事务性?

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

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


8
但是,sqlite的默认Python驱动程序会阻止事务SQL。bugs.python.org/issue10740
joeforker 2013年

因此答案是“是的,除非您使用的是MySQL或更旧的Oracle版本,否则它们可以回滚。”
rjmunro 2015年

不,除了列出的数据库外,还有其他SQL数据库。
joeforker

3
MariaDB在添加事务性DDL支持方面存在一个未解决的问题:jira.mariadb.org/browse/MDEV-4259。请投票。
吉利

1
ALTER TABLESQLite的有限语句也可以回滚。文档中未明确提及。提到的是如何在事务内部执行“高级”更改。
托马斯

32

PostgreSQL对大多数数据库对象(某些表,索引等,但没有数据库,用户)具有事务性DDL。但是,实际上,任何DDL都会ACCESS EXCLUSIVE锁定目标对象,从而使其完全无法访问,直到DDL事务完成。此外,并非所有情况都得到了很好的处理-例如,如果您尝试foo在另一个事务删除它并创建替换表的同时从表中进行选择foo,那么被阻塞的事务将最终收到错误,而不是查找新foo表。(编辑:此问题已在PostgreSQL 9.3或更高版本中修复)

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

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


我认为如果foo在另一个事务正在删除并重新创建它的情况下尝试从表中进行选择,那么我对旧版本或错误是可以的。我对新版本不满意,因为它尚未提交,所以我一定看不到。我可以接受一个错误,因为在并发事务访问中,无论如何都必须准备重新启动事务。如果错误发生的次数多于必要的次数,则可能会降低性能,但这仍然是正确的。
Jan Hudec 2014年

1
@JanHudec:您不会看到新表的未提交版本,只会看到删除/重新创建它的整个事务的结果。也就是说,删除,重新创建和重新填充表的事务实际上是从该表中选择其他进程的原子。(但是,即使尝试读取表的架构,所有内容都会被阻止)
araqnid 2014年

5

尽管严格意义上讲不是“回滚”,但如果已将数据库配置为支持FLASHBACK命令,则可以使用FLASHBACK命令撤消这些类型的更改。


5

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

截至2019年:

  • Postgres支持许多版本的事务性DDL。
  • SQLite已支持许多版本的事务性DDL。
  • MySQL 自8.0(于2018年发布)开始支持Atomic DDL

1
应该注意的是,MySQL 8中的Atomic DDL仅引用原子DDL语句,而不引用事务性语句。不论是否为原子的DDL语句,大多数情况下仍会导致隐式提交,因此无法在另一个事务中执行(例如START TRANSACTION ... COMMIT;。因此,如果同一事务中的后一个DDL语句失败,则仍然无法回滚事务中的DDL语句 。 mysql.com/doc/refman/8.0/en/...
Lacek

4

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

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

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

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

解决方法是简单地设置一个失败标志,如果其中一个查询失败,则执行“ drop table tblname”。


1
该死的。我一直在试图弄清楚为什么一个特定的(创建)表在过去一个小时内失败时先前创建的表不会消失。我正在使用MariaDB(XAMPP从MySQL切换到MariaDB),但是情况是一样的。这很愚蠢:|
akinuri
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.