thinkphp3.2.3(5以下)的addAll返回值問題

背景(欲快速解決問題,直接看最後一部分即可)

我們都知道mysql支持一次插入多條數據,如下:
以用戶表user爲例,表結構自增主鍵id、賬號username、密碼password。

insert into user(username,password) values ('fpf','123456'),('pig','258310');

TP藉助PDO連接mysql,完成上述操作。

除了增刪改查,PDO還有一些函數,如lastInsertId(返回最後插入行的ID)、PDOStatement::rowCount(返回上一個由對應的 PDOStatement 對象執行DELETE、 INSERT、或 UPDATE 語句受影響的行數)等。參考1參考2

問題

對於tp3.2.3的addAll方法,發現其返回值與官方文檔說的返回最後一個id不一樣,而是返回第一個id。比如用addAll方法向user表中一次插入1、2、3共三條數據,它返回的是第1條數據的id,而非官方定義的第3條數據的id。

$m=M('User');
$data=[['username'=>'fpf','password'=>'123456'],['username'=>'pig','password'=>'258310']];
$pk=$m->addAll($data);
dump($pk);

運行該帶碼,dump的數據是5,而在數據庫中
id=5對應數據[‘username’=>‘fpf’,‘password’=>‘123456’];
id=6對應數據[‘username’=>‘pig’,‘password’=>‘258310’]。
顯然tp官方文檔定義相悖。

原因

追查TP3.2.3的ORM實現機制發現,其addAll方法的返回值直接用pdo的lastInsertId方法獲得,在tp目錄ThinkPHP\Library\Think\Db下的Driver.class.php文件的execute方法中,具體實現方法如下:

在這裏插入圖片描述問題就在pdo的lastInsertId方法上,它是調用mysql api中的mysql_insert_id函數返回的值。
mysql_insert_id函數和SELECT LAST_INSERT_ID()作用類似,但又有一些區別,在下面代碼情景中作用相同,具體不同看官方文檔,直接在數據庫管理工具(如navicat)上執行下面mysql腳本就會發現問題。

insert into user(username,password) values ('fpf','123456'),('pig','258310');
SELECT LAST_INSERT_ID()

在這裏插入圖片描述實際結果:
在這裏插入圖片描述
從兩個圖片結果可以看到,一次插入兩條,通過SELECT LAST_INSERT_ID()查到的id=24,而實際最後一個id=25,這是什麼原因呢?具體原因可以看看這篇官方對該語句的解釋,這是mysql的一個處理策略,主要是因爲可以輕鬆地實現其他服務器複製相同的INSERT語句。當然,在一次插入一條時,這個現象時不存在的,那麼mysql_insert_id返回的結果也就正確了。
在這裏插入圖片描述

mysql官方文檔介紹mysql_insert_id函數解釋如下:詳細參考官方文檔

官方文檔主要說了mysql_insert_id函數返回的是儲存在有AUTO_INCREMENT約束的字段的值,如果表中的字段不使用AUTO_INCREMENT約束或者使用自己生成的唯一值插入,那麼該函數不會返回你所存儲的值,而是返回NULL或0。因此,在沒有使用AUTO_INCREMENT約束的表中,或者ID是自己生成的唯一ID,lastInsertId函數返回的都是0。

也可以參考這兩篇文章,有實際例子說明,更好,重點看看第一篇。文章1文章2

解決方案

利用pdo的rowCount方法,具體代碼如下:
原理:lastID=firstID+rowCount-1;
在這裏插入圖片描述具這樣修改TP3.2.3的addAll方法就可以正常放回最後一行的id了。
樣另外TP5及以上一次插入多條的方法是insertAll,它返回的是添加成功的條數,當然,這些方法的前提都是插入執行成功。將tp3.2.3目錄ThinkPHP\Library\Think\Db下的Driver.class.php文件的execute方法改成下圖即可:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章