php - 未找到基表或 View - 尽管应该找到

标签 php mysql mariadb

我有一个 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 命令DROPCREATE 都在受影响的表上应用TABLE_LOCK。这意味着在 DELETE 释放 TABLE_LOCK 之前,您的 CREATE 不会执行。

可能发生的情况是命令的运行顺序可能如下所示:(因为与前几个 INSERTS< 相比,准备和排队 CREATE 命令需要更长的时间)

  1. 删除表(锁定表)
  2. 插入...
  3. 插入...
  4. 插入...
  5. CREATE TABLE(锁定表)
  6. 插入...

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/

相关文章:

javascript - UniSharp/laravel-ckeditor 在 laravel 5.7 中不工作

php - SQL - 查询运行非常慢

PHP和MySQL两次查询输出数据

php - 将 iPhone HTTP 请求发送到 Apache PHP 网络服务器

mysql - 在 Django 中,尝试转储数据时得到 "Error: Unable to serialize database"?

MySQL连接两个表并添加列值

mysql - 对于该服务器版本,其显示在此位置无效

mysql - 查询需要将近两秒钟,但只匹配两行——为什么索引没有帮助?

php - MySQL/MariaDB 不接受 JSON 格式?无法创建数据库

php - 省略非默认字段时,在 MariaDb 上插入失败