問題
PHP の PDO 拡張機能を使用してデータを挿入する場合、最後に挿入されたレコードの ID を戻り情報として取得する必要がある場合があります。どうすればこの要件を達成できるでしょうか?
lastInsertId 関数
PDO の lastInsertId 関数を使用します。
しかし、最近使用中に、lastInsertId 関数が 0 を返す場合があることがわかりました。なぜこのようなことが起こっているのでしょうか?
まず、PHP マニュアルの lastInsertId 関数の説明を見てみましょう。
最後に挿入された行の ID またはシーケンス値を返します。
次の例を見てみましょう。
テスト例
自動インクリメント制約を使用した主キーは ID フィールドです。
1 | <?php $dsn = 'mysql:dbname=test;host=127.0.0.1' ; $user = 'root' ; $password = 'root' ; try { $dbh = new PDO( $dsn , $user , $password ); } catch (PDOException $e ){ echo "Connection failed: " . $e ->getMessage(); } for ( $i = 0; $i < 10; $i ++){ $sql = 'INSERT INTO `tbl_test` (id, name) VALUE (:id, :name)' ; $data = array ( ':id' => '' , ':name' => "user_ $i " ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $data ); } $sql = 'INSERT INTO `tbl_test` (id, name) VALUE (:id, :name)' ; $new_data = array ( ':id' => '' , ':name' => 'user_new' ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $new_data ); $last_id = $dbh ->lastInsertId(); echo 'last id: ' . $last_id ;
|
ログイン後にコピー
結果
last id: 11
主キーは ID フィールドであり、auto は使用されません-インクリメント制約。
1 | <?php $dsn = 'mysql:dbname=test;host=127.0.0.1' ; $user = 'root' ; $password = 'root' ; try { $dbh = new PDO( $dsn , $user , $password ); } catch (PDOException $e ){ echo "Connection failed: " . $e ->getMessage(); } for ( $i = 0; $i < 10; $i ++){ $sql = 'INSERT INTO `tbl_test` (id, name) VALUE (:id, :name)' ; $data = array ( ':id' => $i , ':name' => "user_ $i " ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $data ); } $sql = 'INSERT INTO `tbl_test` (id, name) VALUE (:id, :name)' ; $new_data = array ( ':id' => '' , ':name' => 'user_new' ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $new_data ); $last_id = $dbh ->lastInsertId(); echo 'last id: ' . $last_id ;
|
ログイン後にコピー
結果
last id: 0
主キーは ID フィールドではなく、主キーkey は自動インクリメント制約を使用します。
1 | <?php $dsn = 'mysql:dbname=test;host=127.0.0.1' ; $user = 'root' ; $password = 'root' ; try { $dbh = new PDO( $dsn , $user , $password ); } catch (PDOException $e ){ echo "Connection failed: " . $e ->getMessage(); } for ( $i = 0; $i < 10; $i ++){ $sql = 'INSERT INTO `tbl_test` (tbl_id, name) VALUE (:tbl_id, :name)' ; $data = array ( ':tbl_id' => $i , ':name' => "user_ $i " ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $data ); } $sql = 'INSERT INTO `tbl_test` (tbl_id, name) VALUE (:tbl_id, :name)' ; $new_data = array ( ':tbl_id' => '' , ':name' => 'user_new' ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $new_data ); $last_id = $dbh ->lastInsertId(); echo 'last id: ' . $last_id ;
|
ログイン後にコピー
結果
last id: 11
主キーは ID フィールドではないため、使用されません自動インクリメント制約。
1 | <?php $dsn = 'mysql:dbname=test;host=127.0.0.1' ; $user = 'root' ; $password = 'root' ; try { $dbh = new PDO( $dsn , $user , $password ); } catch (PDOException $e ){ echo "Connection failed: " . $e ->getMessage(); } for ( $i = 0; $i < 10; $i ++){ $sql = 'INSERT INTO `tbl_test` (tbl_id, name) VALUE (:tbl_id, :name)' ; $data = array ( ':tbl_id' => uniqid(), ':name' => "user_ $i " ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $data ); } $sql = 'INSERT INTO `tbl_test` (tbl_id, name) VALUE (:tbl_id, :name)' ; $new_data = array ( ':tbl_id' => uniqid(), ':name' => 'user_new' ); $sth = $dbh ->prepare( $sql ); $sth ->execute( $new_data ); $last_id = $dbh ->lastInsertId(); echo 'last id: ' . $last_id ;
|
ログイン後にコピー
結果
last id: 0
PHP ソースコードを表示
を参照してください。一部の例では 0 が返され、一部の例では最新の ID が返されます。それでは、どのような状況で lastInsertId は 0 を返すのでしょうか?インターネットで多くの情報を検索しましたが、必要な答えが見つかりませんでした。PHP ソース コードを開いたところ、関数 last_insert_id の実装ソース コードが次のとおりであることがわかりました。 > ご覧のとおり、関数によって返される ID 値は、mysql API の mysql_insert_id 関数を呼び出して返される値です。
mysql マニュアルを表示
mysql マニュアルを開いて次の段落を見つけてください:
mysql_insert_id() は、値が AUTO_INCREMENT カラムに格納されているかどうかに関係なく、AUTO_INCREMENT カラムに格納された値を返します。 NULL または 0 を格納することによって自動的に生成されるか、明示的な値として指定された LAST_INSERT_ID() は、NULL または 0 以外の明示的な値を格納する場合、LAST_INSERT_ID() によって返される値には影響しません。 🎜>
結論
マニュアルの説明から、テーブル内のフィールドが AUTO_INCREMENT 制約を使用していない場合、mysql_insert_id 関数はフィールドに格納されている値を返すことがわかります。 AUTO_INCREMENT 制約を使用するか、独自に生成された一意の値を使用する場合、関数は保存した値を返さず、代わりに NULL または 0 を返します。したがって、AUTO_INCREMENT 制約を使用しないテーブル、または ID が自己生成された一意の ID であるテーブルでは、lastInsertId 関数は 0 を返します。
この記事では問題の理由について説明していますが、私の個人的なレベルに限界があるため、ご提案やご批判がございましたら、お気軽にご指摘ください。
注: この記事では PHP5.4.15、MySQL5.5.41 を使用しています。