Я видел этот вопрос раньше, но все решения для меня не работают. Главное решение - сохранить результат, что я уже делаю. Большинство людей говорят, что я выполняю 2 одновременных запроса, которых я не понимаю. Возможно, я использовал эту функцию ниже более одного раза, но я всегда освобождаю и закрываю оператор, поэтому не уверен, почему это происходит.

Скорее всего, вы можете игнорировать верхнюю половину функции, которая просто генерирует строку для представления типов. Это полный класс БД, который я сделал:

(Я отредактировал его, так как изначально опубликовал и заменил self :: $ connection на self :: $ db)

class DB {
    private static $dbhost = "localhost";
    private static $dbuser = "some_user"; // placeholder
    private static $dbpass = "some_assword"; // placeholder
    private static $dbname = "database_name"; // placeholder
    private static $db;

    public static function connect() {          
        self::$db = new mysqli(self::$dbhost,  self::$dbuser, self::$dbpass, self::$dbname);        
        if (self::$db->connect_errno) {
            die("Database mysqli failed: " .
                self::$db->connect_error . " (" . 
                self::$db->connect_errno . ")"      
            );
        }
    }

    // IGNORE THIS! It just formats the parameters for the 
    // call_user_func_array function to work correctly.
    private static function getBindings(&$params) {
        $types = "";        
        $bindings = array();
        foreach ($params as $value) {
            switch (gettype($value)) {
                case "integer":
                    $types .= "i";
                    break;
                case "double":
                    $types .= "d";
                    break;
                case "string":
                    $types .= "s";
                    break;
                default: 
                    $types .= "s";
                    break;
            }
        }       
        foreach($params as $key => $value)
            $bindings[$key] = &$params[$key]; // assign to references (because bind_param requires references)      
        // to add a string of variable types to the start of the $bindings array (such as 'sss')
        array_unshift($bindings, $types);
        return $bindings;
    }

    public static function query($query, $params) {
        if (!isset(self::$db)) { self::connect(); }

        if (empty($params)) {
            // prepared statement not needed
            return self::$db->query($query);
        }

        $successful = false;
        $bindings = self::getBindings($params);

        // MySQL prepared statement execution:
        $statement = self::$db->prepare($query);
        call_user_func_array(array($statement, 'bind_param'), $bindings);       
        $statement->execute();
        $statement->store_result(); 

        if ($statement->num_rows > 0) {
            // for select queries
            $successful = $statement->get_result(); // does not work! (returns boolean)

            echo self::$db->errno; // 2014          
            echo "<br />";
            echo self::$db->error; // Commands out of sync; you can't run this command now
            echo "<br />";      

            // this method works fine (but I need to return the result set!):
            /*$name = false; $link = false;
            $statement->bind_result($name, $link);

           while ($statement->fetch()) {
                echo 'name: '.$name.'<br>';
                echo 'link: '.$link.'<br>';
           }*/
        } else if ($statement->affected_rows > 0) {
            // for insert queries
            $successful = true;
        }       

        $statement->free_result();
        $statement->close();
        return $successful;
    }

    public static function close() {
        if (isset(self::$db)) self::$db->close();
    }
}

EDIT: так выглядит один из моих запросов (я запросил 2 запроса на этой же странице, используя свой класс DB и функцию DB :: query (...)):

$result = DB::query("SELECT * FROM table_name;");
if ($result) {
    while ($row = $result->fetch_assoc()) {
        // do stuff                             
    }
    $result->close();
}
1
Mayron 21 Фев 2016 в 16:14

2 ответа

Лучший ответ

Ради всего здравого смысла измените драйвер на PDO и сделайте весь этот код в

public static function query($query, $params = NULL)
{
    if (!$params) {
        return self::$connection->query($query);
    }

    $statement = self::$connection->prepare($query);
    $statement->execute($params);
    return $statement;
}

Использоваться таким образом

$result = DB::query("SELECT * FROM table_name");
foreach($result as  $row) {
    // do stuff                             
}
3
Your Common Sense 21 Фев 2016 в 14:24

Документация MySQL относительно несинхронизированных команд предложите две возможности:

  1. Вы использовали результат и пытаетесь выполнить новый запрос перед освобождением последнего результата.
  2. Вы выполняете два запроса (не обязательно одновременно), не используя и не сохраняя результат между каждым из них.

Логика в вашем коде показывает, что единственная ситуация, когда вы не освобождаете результаты, - это когда подготовленный оператор не требуется. Ответ на вашу проблему может заключаться в том, чтобы разобраться с этим конкретным результатом и освободить или сохранить его.

Я вижу из вашего кода self::$connection - это статическая ссылка, поэтому вполне возможно, что любой запрос, выполняемый в этой области, использует то же соединение. Трудно сказать, не имея возможности увидеть весь свой класс.

-1
HenryTK 21 Фев 2016 в 13:43