【发布时间】:2011-12-29 11:05:15
【问题描述】:
我有一个 PHP 脚本,它从数据库中删除旧数据,从另一个数据库中读取数据,然后将新数据插入第一个。出于显而易见的原因,我想使用事务来回滚每个可能的错误。这似乎行得通,除了一些意想不到的 - 对我来说 - 无法解释的行为。
当(故意)中断脚本时,我的所有 DELETE 语句都成功回滚,除了似乎已经执行的语句。
代码有一个“任务”数组,每个数组都包含表名、对数据类型的可读描述以及源数据库的特定 SELECT 语句等详细信息。这是“工作清单”数组的一个片段:
$worklist = array(
array(
"table" => "campaign",
"description" => "campaign details",
"selectsql" => "SELECT ... "
),
array(
"table" => "product",
"description" => "product",
"selectsql" => "SELECT ... "
),
...
array(
"table" => "context_search",
"description" => "product details for search",
"selectsql" => "SELECT ... "
)
);
定义这个“工作清单”后,我开始我的交易如下:
$dbfront = new PDO(...);
$dbfront->exec("SET AUTOCOMMIT = 0");
$dbfront->beginTransaction();
$dbfront->exec("SET FOREIGN_KEY_CHECKS=0");
之后我循环遍历工作列表以删除旧数据,如下所示:
foreach($worklist as $job){
$deleter = $dbfront->prepare("DELETE FROM "
. $job["table"] .
" WHERE
campaign_id = " . $campaign_id .
";");
try{
$deleter->execute();
echo $deleter->rowCount() . "lines of old data deleted from " . $job["table"] . " table\n";
} catch (exception $e){
echo $e . "\n";
$dbfront->rollBack();
echo "An error occurred. All changes have been rolled back.\n";
exit;
}
}
然后,有从另一个数据库中选择新数据并将其插入“dbfront”的代码,最后,我有这部分来提交更改:
try {
$dbfront->commit();
echo "\nAll changes committed\n";
} catch (Exception $e) {
echo $e . "\n";
$dbfront->rollBack();
echo "An error occurred. All changes have been rolled back.\n";
exit;
}
有谁知道当我中途中断这个脚本时前两个表完美回滚,而第三个表无论如何都要执行的合理解释是什么?
【问题讨论】:
-
事务的提交部分是否适用于不同的表 - 也许不是 InnoDB 的表?
-
说实话,这种东西更适合存储过程(尤其是sa系列的原子删除)......
-
我会选择 Darhazer。在 mysql 客户端中尝试 SHOW TABLE STATUS 并查找任何非 InnoDB 表并检查它们是否是事务性的。
-
宾果游戏。这是一个 MyISAM 表。为什么?我一点头绪都没有。我想我现在要去让一个数据库设计师被画出来,分成四等份并斩首。如果您可以将您的答案作为“答案”,那么我可以接受它作为正确的答案,Darhazer。非常感谢。要是我一周前来这里就好了。
标签: php mysql transactions pdo