我有一个PHP脚本,从一个数据库中删除旧数据,从另一个数据库中读取数据,然后在第一个数据库中插入新数据。出于显而易见的原因,我希望使用事务来实现这一点,并对每个可能的错误进行回滚。这似乎是有效的,除了一点意想不到的和-对我来说-无法解释的行为。
当(有目的地)中断脚本时,我的所有DELETE语句都被成功回滚,除了一个似乎已经执行的语句。
代码有一个"任务"数组,每个任务都包含一个表名,一个人类可读的数据类型描述,以及源数据库的特定SELECT语句。下面是'worklist'数组的一个片段:
$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;
}
有没有人知道,当我中途中断这个脚本时,前两个表被完美回滚,而第三个表无论如何都要执行,这可能是一个合理的解释?
不是所有的MySQL存储引擎都支持事务。如果事务在MyISAM表上操作,那么无论事务的其余部分是提交还是回滚,都将提交该表中的更改。