我有一个 mysql 表,每天自动更新一次。执行此更新的脚本类似于下面的 PHP 代码。它的基本功能是创建一个具有相同结构的临时表,首先将所有数据插入其中,然后截断实际表并插入临时表中的数据。最后临时表被销毁。使用此方法是因为它显着降低了实际表的停机时间。
这在相当长的一段时间内运行良好。直到最近,随着 Debian 的升级(从 Debian 8 到 Debian 9,这也意味着从 MySQL 到 MariaDB 的切换)。现在我经常在日志文件中找到这样的错误消息:
[Wed Sep 27 06:03:04.903652 2017] [:error] [pid 27393] [client 127.0.0.1:36794] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database.table_temp' doesn't exist in /someFile.php:50\nStack trace:\n#0 /someFile.php(50): PDOStatement->execute()\n#1 {main}\n thrown in /someFile.php on line 50
此错误最终会导致部分数据丢失。如果我理解正确的话,它说临时表在插入完成之前就被销毁了,对吗?但这怎么可能发生,考虑到这并不是真正的临时表,我只是使用一个真实的表并将其命名为临时表。 MariaDB 是否会延迟 INSERT,以便 php 脚本可以在 INSERT 完成之前执行 DROP?
这是 cron.d 条目,因此该脚本实际上每天只执行一次:
1 6 * * * root /usr/bin/wget -q http://www.example.com/someFile.php -O /dev/null
还值得注意的是,脚本在一两个小时内执行完毕,因此前一天的执行早已完成,不会干扰。
这基本上是代码:
$dataArray = []; // much data
$db->query("DROP TABLE IF EXISTS `table_temp`;");
$db->query("CREATE TABLE `table_temp` LIKE `table`;");
$tres = $db->prepare("
INSERT INTO `table_temp`
(`field1`, `field2`)
VALUES
(:field1, :field2)
");
foreach($dataArray as $data){
$db->beginTransaction();
$res->execute();
foreach($data as $item){
$tres->bindParam('field1', $item['field1'], PDO::PARAM_INT);
$tres->bindParam('field2', $item['field2']);
$tres->execute(); // line 50
}
$db->commit();
}
$db->query("RENAME TABLE `table` TO `table_old`, `table_temp` TO `table`");
$db->query("DROP TABLE `table_old`");
最佳答案
下降;创造; (可能是一把锁)
因锁而延迟的命令会按照调用顺序添加到“队列”中。
mySql 命令DROP
和CREATE
都在受影响的表上应用TABLE_LOCK
。这意味着在 DELETE
释放 TABLE_LOCK
之前,您的 CREATE
不会执行。
可能发生的情况是命令的运行顺序可能如下所示:(因为与前几个 INSERTS< 相比,准备和排队
)CREATE
命令需要更长的时间
- 删除表(锁定表)
- 插入...
- 插入...
- 插入...
- CREATE TABLE(锁定表)
- 插入...
PHP 不会等待 mysql 命令完成...
...它只是继续以愉快的方式发送命令。 这是您问题的根源。
innoDB 事务
无法使用事务来解决问题。 CREATE and DROP will commit a transaction .
仔细查看您的 $db
对象。
使用将根据成功执行查询返回结果的一个,例如 PDO::exec 。然后您应该能够将INSERT
语句包装在条件 block 中(其中PHP 必须等待响应才能检查条件)。
$result = $db->exec('CREATE ...');
if (false !== $result && $result >= 0) {
foreach($dataArray as $data){
// INSERT
}
}
关于php - 未找到基表或 View - 尽管应该找到,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46471894/