我想知道是否有任何原因导致mysqli事务无法在php fork中正常工作(使用pcntl_fork())?
我有一个脚本,该脚本在php fork中调用另一个脚本,在第二个脚本中,我以事务模式进行一些数据库操作。我愿意在这些操作中插入一个错误的查询,该操作应该停止脚本并回滚db操作。事实是该脚本已按预期停止,但是数据库中存在数据库更改(未调用提交)。
我尝试在分支之外手动启动第二个脚本,并且行为符合预期,因此问题必须出在分支上。
有什么主意吗?
(我可以在需要时发布我的代码,但这有点浓密,很难阅读...)
编辑:伪代码示例:
分叉脚本:
$pid = pcntl_fork();
if ($pid < 0) {
errorHandling;
} else if ($pid == 0) {// In the son
sleep(1); // Waiting the father register the son's pid
$this->pid = getmypid();
$this->worker = $workerManager->fetchBy(array('pid' => $this->pid)); // Get the worker object from db. It contains info about the fork in order to cleanup when it finished the work.
$this->launchScript($this->worker->getAction()); // This function just call session_write_close in the son and includes the second script
} else { // In the father
$worker = new Worker($pid); // Create the db object I talked about in the son
$workerManager->create($worker); // Put it in db
Ajax::Response(OK, "Launched", $pid); // Answer the request and exits the process (without waiting the son, this is done by a cron elsewere)
}
第二个脚本伪代码:
$db = new DB_Cognix(); // Just a mysqli encapsulation
$db->enableTransaction(); // Calls $mysqli->begin_transaction()
try {
/*
** Some DB operations (Inserts, Updates and Selects)
*/
$db->query("FOOBARBAZ"); // A bad query, the db encapsulation will throw an Exception.
} catch (Throwable $e) {
$db->rollback(); // calls mysqli::rollback()
$worker->setErrorMessage($e->getMessage());
$workerManager->update($worker); // This uses another db object and is not concerned by the transaction
exit;
}
$db->commit(); // Calls mysqli::commit();
exit("OK");
第二个脚本在退出时停止;并且在数据库中更新了工作程序,但是无论如何都执行了数据库操作。 当直接从浏览器中调用第二个脚本时,它运行良好,回滚已完成。
编辑2:我尝试了一个非常简单的代码来查看是否是fork的原因,并且它像一个符咒一样工作,所以我认为问题不在于fork ...
<?php
$pid = pcntl_fork();
if ($pid < 0) {
exit("ERROR: Fork failed!");
} else if ($pid == 0) {
session_write_close();
fastcgi_finish_request();
$db = new DB_Cognix("", true);
$db->enableTransaction();
for ($i = 0; $i < 10; ++$i) {
$db->query("INSERT INTO Tests (id1, id2) VALUES ($i, $i)");
}
$db->rollback();
exit();
} else {
echo "Child launched";
session_write_close();
fastcgi_finish_request();
$status = 0;
pcntl_waitpid($pid, $status);
exit;
}
?>