PHP pdo lastInsertId () всегда возвращает 0 - PullRequest
0 голосов
/ 09 июля 2020

Вот база данных и PHP информация:

  • Производитель и версия базы данных: 10.2.32-MariaDB
  • PHP Версия: PHP 7.3

У меня возникла проблема при попытке получить последний вставленный идентификатор для использования в другом операторе вставки с использованием PHP PDO и MariaDB ...

Извините за расплывчатый псевдокод ниже но пытаюсь замаскировать проприетарные данные:

try {
    include_once $pdo connection stuff here;
    $pdo->beginTransaction();
    $sql = 'AN INSERT STATEMENT HERE';
    $stmt = $pdo->prepare($sql);
    $stmt->bindValue(':some_value', $some_value);
    $stmt->bindValue(':another_one', $another_one);
    $stmt->bindValue(':additional_value', $additional_value);
    $stmt->execute();
    // have tried to call $pdo->commit(): here to no avail.
     //should get the last inserted id here on the AUTO_INCREMENT column in the target table from above prepared statement
    // the AI column is not included in the insert statement above nor any value specified in the VALUES clause so should
    // set to the next available value (and does so according to peeking at row over in phpMyAdmin).
    $last_insert_id = $pdo->lastInsertId();

    // don't really want to commit the above insert here just yet in case something goes wrong below and can rollback
    // a file could be uploaded but it's not mandatory
    if (!empty($_FILES['some_file'])) { // file has been attached.
        // some file operations here
        // some file operations here
        // some file operations here
        // some file operations here
        $extensions = array("extension I am expecting");
        if (in_array($file_ext, $extensions) === false) {
            //Uh-oh not the correct extension so rolling back
            $pdo->rollback();
            die('message here...');
        } else {
            // file type is ok so proceeding
            // if the file already exists, get rid of it so we don't have 2 copies on the server
            if (file_exists($file_dir.$file_name)) {
               unlink($file_dir.$file_name);
            }
            // storing the attached file in designated directory
            move_uploaded_file($file_tmp, $file_dir.$file_name);
            // going to parse the file...
            $xml = simplexml_load_file('xml file to parse');
           // have tried to call $pdo->commit(): here to no avail.
            foreach ($xml->children() as $row) {
                foreach ($row as $obj) {
                    if (some checking things with the obj here yada yada yada) {
                        $insert_sql = "INSERT INTO another table(columns.....) //there is no AUTO_INCREMENT column attribute on any column in this table just FYI
                        VALUES(column values...)";
                        $stmt = $pdo->prepare($insert_sql);
                         // want the AI value here from the very first insert above but it's always zero (0)
                        $stmt->bindValue(':last_insert_id', intval($last_insert_id), PDO::PARAM_INT);
                        $stmt->bindValue(':some_column', strval($some_column));
                        $stmt->bindValue(':another_one', strval($another_one));
                        $stmt->execute(); 
                    }
                }
            }
            // all is good so committing the first insert
            $pdo->commit();
        }
    } else {
        // the file was not uploaded and it is not mandatory so committing the first insert here and the second insert never happens
        $pdo->commit();
    }

} catch (Exception $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollback();
    } 
    throw $e;
    echo 'An error occurred.';
    echo 'Database Error '. $e->getMessage(). ' in '. $e->getFile().
    ': '. $e->getLine();   
}
}

Моя цель состоит в том, чтобы всегда вставлялась первая вставка (если ничего не произойдет). Вторая вставка является необязательной в зависимости от того, прикреплен ли файл. Если файл прикреплен и все операции с файлом выполнены правильно, я вставлю некоторые значения в другую таблицу и буду использовать значение auto_increment из первой вставки во вторую таблицу (идея - внешний ключ).

Но по какой-то причине вставленное значение всегда равно нулю (0).

Когда код выполняется успешно, обе вставки таблиц завершены (при условии, что файл присутствует, а вторая вставка даже срабатывает) ... Строка в первой таблице создается и создается 1 или более строк во второй таблице вставки, но они имеют значение 0 в назначенном столбце, где я ожидал бы, что они будут содержать значение AI из первой вставки ...

Я пытался вызвать $pdo->commit() в нескольких других местах, которые "имеют смысл" для меня, думая, что первая вставка должна быть сделана для того, чтобы значение AI даже существовало в этой таблице, но не повезло ни с одним из них .. .

Я даже пробовал это, я видел в другом сообщении Stackoverflow как тест, чтобы убедиться, что PDO не делает ничего плохого, но PDO i в порядке ...

$conn = new PDO(connection info here);

$conn->exec('CREATE TABLE testIncrement ' .
            '(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50))');
$sth = $conn->prepare('INSERT INTO testIncrement (name) VALUES (:name)');
$sth->execute([':name' => 'foo']);
var_dump($conn->lastInsertId());

И приведенное выше возвращает: string(1) "1"

Итак, я думаю, что PDO в порядке (при условии, что указанное выше не было заключено в транзакцию, и я не пробовал это еще)

Надеюсь, я предоставил достаточно четких деталей ... Кто-нибудь знает, почему я получаю 0, а не последний идентификатор вставки?

Любая помощь очень ценится и спасибо!

1 Ответ

0 голосов
/ 09 июля 2020

Вам нужно проверить результат $ stmt-> execute. Прочтите документацию по PDOStatement :: execute , и вы увидите, что он возвращает логическое значение:

Возвращает TRUE в случае успеха или FALSE в случае неудачи.

Затем прочтите документацию по PDOStatement :: errorInfo . Отметьте это, если execute возвращает FALSE.

$stmt->execute();

echo "\nPDOStatement::errorInfo():\n";
$arr = $stmt->errorInfo();
print_r($arr);

EDIT: обычно не рекомендуется выводить ошибки на экран, я сделал это в данном случае для удобства. Лучшим подходом было бы написать файл журнала:

$arr = $stmt->errorInfo();
file_put_contents("/path/to/file.log", print_r($arr, TRUE));

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...