【问题标题】:INSERT not complete before SELECT query在 SELECT 查询之前 INSERT 未完成
【发布时间】:2021-07-12 14:47:21
【问题描述】:

我有一个 PHP 脚本,它被分成两个单独的 PHP 脚本(因为它们每个都有一个目的并且很长)。为简单起见,我们称它们为 1.php 和 2.php。

脚本 1.php 对网站进行 API 调用,将有效负载传递给函数。一旦截断并将新记录插入表中,它就会包含第二个脚本。这就是问题开始的地方。似乎当我查询 marketPlace 表时,它返回一个空数组,但是如果我在包含 2.php 之前插入一个 sleep(1) 它可以工作!我只能总结一下,在调用下一个查询之前,1.php 中的截断和插入查询尚未完成? (我以前从未遇到过这种情况!)。

只有一个数据库连接,由1.php中包含的数据库类定义:

class Database
{

    // This class allows us to access the database from any function with ease
    // Just call it with Database::$conn

    /** TRUE if static variables have been initialized. FALSE otherwise
    */
    private static $init = FALSE;
    /** The mysqli connection object
    */
    public static $conn;
    /** initializes the static class variables. Only runs initialization once.
    * does not return anything.
    */
    public static function initialize()
    {


        Global $servername;
        Global $username;
        Global $password;
        Global $dbname;

        try {

            if (self::$init===TRUE)return;
            self::$init = TRUE;
            self::$conn = new mysqli($servername, $username, $password, $dbname);

        }

        catch (exception $e) {
            date('Y-m-d H:i:s',time()) . " Cant' connect to MySQL Database - re-trying" . PHP_EOL;
        }
    }

    public static function checkDB()
    {

        if (!mysqli_ping(self::$conn)) {
            self::$init = FALSE;
            self::initialize();
        }

    }

}

截断并插入市场的函数是:

function processMarketplace($marketData) {

    // Decode to JSON
    $outputj = json_decode($marketData, true);
    $marketplaceCounter = 0;

    // Check for success
    if (($outputj['success']==true) && (!stristr($marketData, "error"))) {

        // Create the blank multiple sql statement
        $sql = "TRUNCATE marketplace;";  // Clears down the current marketPlace table ready for new INSERTS

        //Loop through each multicall
        foreach ($outputj['multiCall'] as $orderBook) {
            foreach ($orderBook['marketplace'] as $orderLine) {

                $type = $orderLine['type'];
                $price = $orderLine['amountCurrency'];

                // Add new SQL record (This ignores any duplicate values)
                $sql .="INSERT IGNORE INTO marketplace (type, price) VALUES ('" . $type . "'," . $price . ");";

            }

            $marketplaceCounter++;

        }

        // Now run all the SQL's to update database table
        if (strlen($sql) > 0) {
            if (Database::$conn->multi_query($sql) === TRUE) {
                 echo mysqli_error(Database::$conn);
                //echo "New records created successfully";
            } else {
                echo mysqli_error(Database::$conn);
                echo "Error: " . $sql . "<br>" . Database::$conn->error;
            }
        }

        echo date('Y-m-d H:i:s',time()) . " == Marketplace Orderbook retreived == <BR><BR>" . PHP_EOL;

    } else {

        echo date('Y-m-d H:i:s',time()) . " Failed to get Marketplace data. Output was: " . $marketData . "<BR>" . PHP_EOL;
        die();
    }

}

我已经追了好几个小时了,我真的不明白为什么在我调用 processMarketplace() 函数后添加 sleep(1) 延迟会有所帮助。我还尝试将 1.php 和 2.php 合并为一个脚本,这会产生相同的结果。 2.php 只需执行SELECT * FROM marketPlace 查询,除非我有sleep(1),否则返回NULL。

我是错过了一些简单的事情还是我真的很糟糕?

我应该添加我正在使用 InnoDB 表。

在 1.php 中是这样调用的:

$marketData = getData($user,$api); // Get Marketplace Data
processMarketplace($marketData); // Process marketplace data
sleep(1); // Bizzare sleep needed for the select statement that follows in 2.php to return non-null
include "2.php"; // Include 2nd script to do some select statements on marketPlace table

2.php 包含以下调用:

$typeArray = array('1','2','3');
foreach ($typeArray as $type) {

    initialPopulate($type);

}

函数 initialPopulate($type) {

// Reset supplementary prices
mysqli_query(Database::$conn, "UPDATE marketPlace SET price_curr = '999999' WHERE type='" . $type . "'");
echo mysqli_error(Database::$conn);

// Get marketplace data <--- This is the one that is strangely returning Null (after the first loop) unless I place the sleep(1) before including 1.php
$query = "SELECT * FROM marketPlace WHERE type='" . $type . "'";
$result = mysqli_query(Database::$conn, $query);echo mysqli_error(Database::$conn);
$resultNumRows = mysqli_num_rows($result);echo mysqli_error(Database::$conn);

// Create array from mysql data
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
    $rows[] = $r;
}

// Get information from the offertypes table
$query2 = "SELECT offerID FROM queryTypes WHERE type='" . $type . "'";
$result2 = mysqli_query(Database::$conn, $query2);echo mysqli_error(Database::$conn);

// Create array from mysql data
$rows2 = array();
while($r2 = mysqli_fetch_row($result2)) {
    $rows2[] = $r2;
}

// Loop through marketplace data and apply data from the offertypes table
$sql1 = "";     // Create a blank SQL array that we will use to update the database
$i = 0;
foreach ($rows as $row) {

    $sql1 .= "UPDATE marketPlace SET enrichmentType = " . $rows2[$i][0] . " WHERE type='" . $type . "';";
    $i++;
}

// Now run all the SQL's to update database table
if (strlen($sql1) > 0) {
    if (Database::$conn->multi_query($sql1) === TRUE) {
         echo mysqli_error(Database::$conn);
        //echo "New records created successfully";
    } else {
        echo mysqli_error(Database::$conn);
        echo "Error: " . $sql1 . "<br>" . Database::$conn->error;
    }
}

}

【问题讨论】:

  • Absolutley 感谢那里对准备好的语句 Dharman 的反馈 - 我想我只是有点懒惰,因为它是我正在查询的内部服务器系统。
  • 这个问题不是很清楚,我认为它需要更多的代码来理解你想要做什么。您有一个具有$sql = "TRUNCATE marketplace;"; 的processMarketplace() 函数,这显然会截断您的表,因此如果您返回一个空数组,这可能会解释原因。您还提到了 1.php 和 2.php - 这些是您的 Database 类和 processMarketplace() 函数吗?我看不到你在哪里打电话给processMarketplace(),所以这里的执行顺序不清楚。您在哪里插入 sleep(1) 似乎可以让事情正常进行?
  • 很高兴在这里详细说明。 processMarketplace() 函数的目的是清除市场表,然后根据 API 调用(传递给processMarketplace() 函数)的 JSON 有效负载插入新记录。数据库类在 1.php 中声明。 2.php 文件我没有在其中包含任何代码示例,因为我认为它不相关。就本文而言,它只是一个SELECT * FROM marketPlace 查询。sleep(1) 是在调用processMarketplace() 之后添加的。我会对主帖做一些调整。
  • 我仍然认为包含 2.php 以向我们展示如何调用 processMarketplace() 以及在此之前/之后调用的其他内容会很有帮助。 1.php 比数据库类有 more 吗?还是那是整个文件?
  • 您需要致电mysqli_use_result 或mysqli_store_result。见php.net/manual/en/mysqli.use-result.php

标签: php mysql mysqli


【解决方案1】:

您正在使用mysqli:multi_query。 与query 不同,multi_query 不会立即检索结果。检索结果必须使用mysqli::use_result

文档中的一个示例:



/* execute multi query */
if ($mysqli->multi_query($query)) {
    do {
        /* store first result set */
        if ($result = $mysqli->use_result()) {
            while ($row = $result->fetch_row()) {
                printf("%s\n", $row[0]);
            }
            $result->close();
        }
        /* print divider */
        if ($mysqli->more_results()) {
            printf("-----------------\n");
        }
    } while ($mysqli->next_result());
}

您不需要打印结果,但如果您不检索它们,则不能保证 INSERT 已完成。

use_result 的文档中的注释位于 https://www.php.net/manual/en/mysqli.use-result.php

说明

"必须调用 this 或 mysqli_store_result() 函数 在可以检索查询结果之前,以及其中一个或另一个 必须调用以防止对该数据库连接的下一个查询 避免失败。”

由于未调用 store_result 或 use_result,您将得到不可预知的结果。

【讨论】:

  • 非常感谢加尔。我会试一试,很快就会回来报告。
  • 非常感谢 - 这确实是问题所在。看起来我的第二个脚本中也有这个问题!如此奇怪,因为我以前完全按照文档所述的方式完成了此操作,但由于某种原因改变了我这次的操作方式。再次感谢 Garr Godfrey、WOUNDEDStevenJones 和 Dharman 的所有帮助。现在已经解决了。
  • 很高兴听到!既然这回答了你的问题,请确保accept this answer。
猜你喜欢
  • 2014-01-03
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
相关资源
最近更新 更多