MySQL回滚实际上没有回滚

3

我有以下的PHP代码:

$dbh->beginTransaction();
$dbh->exec("LOCK TABLES
    `reservations` WRITE, `settings` WRITE");
$dbh->exec("CREATE TEMPORARY TABLE
        temp_reservations
    SELECT * FROM reservations");
$dbh->exec("ALTER TABLE
        `temp_reservations`
    ADD INDEX ( conf_num ) ; ");

// [...Other stuff here with temp_reservations...]

$dbh->exec("DELETE QUICK FROM `reservations`");
$dbh->exec("OPTIMIZE TABLE `reservations`");
$dbh->exec("INSERT INTO `reservations` SELECT * FROM temp_reservations");

var_dump(GlobalContainer::$dbh->inTransaction()); // true
$dbh->exec("UNLOCK TABLES");
$dbh->rollBack();

对于常规更新/插入,交易正常工作,但由于某种原因上述代码不起作用。当出现错误时,我留下了一个完全空的reservations表。我在PDO::beginTransaction页面上阅读到:“一些数据库(包括MySQL)在事务中发出数据库定义语言(DDL)语句(例如DROP TABLE或CREATE TABLE)时自动发出隐式COMMIT。” MySQL manual列出了“数据定义语句”的列表,我认为这与上面提到的DDL相同,其中列出了CREATE TABLE,但我只创建了一个临时表。有没有什么办法可以解决这个问题?

此外,我留下了一个空的reservations表,这是否表明在DELETE QUICK FROM reservations查询之后发生了提交?

编辑:另外,INSERT INTO reservations行也会产生以下错误:

不能在其他未缓冲的查询活动时执行查询。考虑使用PDOStatement :: fetchAll()。或者,如果您的代码只会针对mysql运行,则可以通过设置PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY属性来启用查询缓冲。 我尝试使用$ dbh-> setAttribute(PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY,true); 但这似乎没有影响它。我认为这可能与事务有关,但我不确定。任何人都可以确定是什么导致了这个错误吗?
1个回答

2

你的OPTIMIZE TABLE语句会导致隐式提交。

我不确定你想要做什么,但是看起来你可以简化你的代码:

$dbh->exec("OPTIMIZE TABLE `reservations`");

所有其他代码只是使工作更加复杂,没有任何收益。
我还假设您正在使用InnoDB表,因为MyISAM表不支持事务。对MyISAM表的每个DDL或DML操作都会立即隐式提交。
顺便说一下,缓冲查询与事务无关。它们与逐行获取SELECT结果集有关,与在PHP中将整个结果集获取到内存中然后迭代有关。请参见以下说明:http://php.net/manual/en/mysqlinfo.concepts.buffering.php

实际上,大部分的“魔法”都发生在被注释掉的那一行,所以仅仅做OPTIMIZE TABLE是不够的。然而,当我多年前编写这段代码时,我使用的是MyISAM,为了确保数据不会损坏,我创建了一个临时表,然后对其进行操作(大约15000个查询),最后将临时表复制到真正的表中,因为这样比在其他查询中出现问题或超时更少风险。但现在我想起来了,我可以在一个事务中完成所有操作,完全不需要使用临时表。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接