我想知道mysqli事务在php fork(使用pcntl\u fork())中不能正常工作是否有任何原因?
我有一个在php fork中调用另一个的脚本,在第二个脚本中,我以事务模式进行了一些数据库操作。我很乐意在这些操作中插入一个错误的查询,它应该停止脚本并回滚db操作。事实上,脚本按预期停止,但数据库中存在数据库更改(没有调用commit)。
我尝试在fork外部手动启动第二个脚本,其行为与预期一致,因此问题一定来自fork。
你知道吗?
(如果需要的话,我可以发布我的代码,但是它有点繁杂而且很难阅读……)
编辑:伪代码示例:
分叉脚本:
$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");
第二个脚本在退出时停止;并且worker在db中更新,但是db操作仍然完成。当直接从我的浏览器调用第二个脚本时,效果很好,回滚就完成了。
编辑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;
}
?>
暂无答案!
目前还没有任何答案,快来回答吧!