我可以将事务与 ALTER TABLE 一起使用吗?
Posted
技术标签:
【中文标题】我可以将事务与 ALTER TABLE 一起使用吗?【英文标题】:Can I use transactions with ALTER TABLE? 【发布时间】:2014-05-13 10:18:59 【问题描述】:我是 SQL 事务的初学者(实际上是新手),所以我可能遗漏了一些明显的东西。
我有这个 SQL 代码,我正在尝试通过 phpMyAdmin 运行:
START TRANSACTION;
INSERT INTO `users` VALUES(NULL, 'User A', 'user.a@example.com', '4', 'User A');
INSERT INTO `users` VALUES(NULL, 'User B', 'user.b@example.com', '3', 'User B');
ALTER TABLE `users` CHANGE `level` `level` TINYINT(3) UNSIGNED NOT NULL;
ALTER TABLE `users` CHANGE `number` `number` INT(10) UNSIGNED NOT NULL;
ALTER TABLE `users` ADD COLUMN `number` INT(10) UNSIGNED NOT NULL AFTER `id`;
COMMIT;
第二个ALTER
导致#1054 - Unknown column 'number' in 'users'
错误。
但是,当它发生在 phpMyAdmin 中时,我可以看到,前两个 INSERT
s(或整个事务)没有回滚。 users
表确实包含两条新记录。
我错过了什么? phpMyAdmin 不支持事务?或者我不明白,事务实际上是如何工作的,这很正常,这两个INSERT
s 在出错的情况下不会回滚?
【问题讨论】:
FWIW 这在 Postgres 中运行良好,这也是一些人更喜欢 Postgres 而不是 mysql 的原因之一。 【参考方案1】:MySQL cause an implicit commit 中的一些语句(最显着的 DDL)在它们被执行和 cannot be rolled back - 因此这也防止了先前的 DML 更改被回滚。 p>
本节中列出的语句(以及它们的任何同义词)隐式结束当前会话中的任何活动事务,就像您在执行语句之前完成了 COMMIT 一样。从 MySQL 5.5.3 开始,大多数这些语句在执行后也会导致隐式提交;有关其他详细信息,请参阅本节末尾。
由于ALTER TABLE
是受影响的语句之一,SQL批处理被有效地处理为:
START TRANSACTION;
INSERT INTO `users` VALUES(NULL, 'User A', 'user.a@example.com', '4', 'User A');
COMMIT; -- prevents ROLLBACK of insert(s), even if DDL fails
ALTER TABLE `users` CHANGE `level` `level` TINYINT(3) UNSIGNED NOT NULL;
建议的解决方案是keep DDL and DML separated。 documentation 说:
您应该设计您的 [DML] 事务以不包含此类 [DDL] 语句。如果您在一个无法回滚的事务中提前发出一条语句,然后另一条语句随后失败,则在这种情况下,无法通过发出 ROLLBACK 语句来回滚该事务的全部效果。
【讨论】:
为什么MySQL在执行语句之前决定COMMIT
?它不应该失败,说明需要明确关闭事务。
隐式提交——而不是引发错误——可能源于历史设计/决策,并在古代丢失。虽然可以以任何一种方式提出论点,但重新创建做出各种实现选择的上下文通常并不容易或富有成效。以上是关于我可以将事务与 ALTER TABLE 一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章
Alter Table Engine = InnoDB 可以同时在多个表上运行吗?
是否可以回滚主要 SQL 数据库中的 CREATE TABLE 和 ALTER TABLE 语句?
ALTER TABLE CREATE CONSTRAINT IF NOT EXIST 可能吗?
是否可以将 Spark 中的 data.table 与 Spark Dataframes 一起使用?