背景(欲快速解决问题,直接看最后一部分即可)

我们都知道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方法改成下图即可:

thinkphp3.2.3(5以下)的addAll返回值问题相关推荐

  1. java多线程测试框架(含入参和返回值)

    最近要对一个webservice接口做测试,需测试高并发接口是否会以异常数据返回,编写了如下demo,有类似需求的可以参考下. 注意事项: 1,线程使用了callable接口形式,call相对runa ...

  2. 返回值是内置类型 不能更改_选择通过更改内容类型返回的详细程度,第二部分...

    返回值是内置类型 不能更改 在上一篇文章中 ,我们研究了如何使用MOXy的功能来控制特定实体的数据输出级别. 这篇文章着眼于Jersey 2.x提供的抽象,它允许您定义一组自定义的批注以具有相同的效果 ...

  3. 王亟亟的Python学习之路(10)-函数对象的作用域,函数作为返回值,闭包

    转载请注明出处:王亟亟的大牛之路 本来打算把工作的事周末做掉点,但是发现在外面浪并不能迅速集中投入,为了避免不必要的BUG 还是明天在家做吧,那么久写一篇Python的文章吧,毕竟背着Mac出门不做些 ...

  4. springboot 自定义返回值处理器HandlerMethodReturnValueHandler

    WEB开发中有这样的需求: 返回给前台的数据需要有统一格式.但是在controller的每个mapping中手写包装很是麻烦,所以可以自定义返回值处理器进行结果包装. 文章目录 返回给前台的消息格式 ...

  5. Redis 笔记(10)— 发布订阅模式(发布订阅单个信道、订阅信道后的返回值分类、发布订阅多个信道)

    1. 发布-订阅概念 发布-订阅 模式包含两种角色,分别为发布者和订阅者. 订阅者可以订阅一个或者若干个频道(channel): 而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都可以收到此消 ...

  6. Go 学习笔记(61)— Go 高阶函数、函数作为一等公民(函数作为输入参数、返回值、变量)的写法

    函数在 Go 语言中属于"一等公民(First-Class Citizen)"拥有"一等公民"待遇的语法元素可以如下使用 可以存储在变量中: 可以作为参数传递给 ...

  7. Python 函数参数有冒号 声明后有- 箭头 返回值注释 参数类型注释

    在python3.7 环境下 函数声明时能在参数后加冒号,如图: 1 def f(ham: str, eggs: str = 'eggs') -> str : 2 print("Ann ...

  8. [JS]请给Array本地对象增加一个原型方法,它用于删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

    请给Array本地对象增加一个原型方法,它用于删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组. 刚开始复习js题还不太习惯 CSDN上看了一个帖子,说是牛客上的标答, ...

  9. 微信小程序根据后台返回值设置自己想要的结果

    今天做微信小程序充值列表 其中微信或者支付后台返回的是1和2 , 那么就需要判断返回值是否为1或者是2然后在改变 简单的就是在xml中判断下就行了 <view class='recharge_t ...

最新文章

  1. (C++)高精度整数的存储、读入、比较和四则运算
  2. Win2003下Exchange2003部署图解之六
  3. JavaScript window
  4. 第二章 向量(d2)有序向量:二分查找
  5. java transient 和Volatile关键字
  6. spring 事务 配置 多个
  7. 定时创建oracle索引,oracle数据库关于索引建立及使用的详细介绍
  8. Dijkstra算法——计算一个点到其他所有点的最短路径的算法
  9. 关于STM32的两个小问题的总结
  10. php 向公众号发送消息,微信公众号之主动给用户发送消息功能
  11. html如何查找文件,如何查找网站上HTML的CLASS文件并下?如何查找网站上HTM 爱问知识人...
  12. [MySQL Bug]DDL操作导致备库复制中断
  13. Mac上emacs标记快捷键
  14. 十大经典排序算法(动图演示)-转载
  15. Ubuntu 12.04设置豆沙绿
  16. 三相逆变器双pi控制器参数如何调节_光伏逆变器MPPT基本原理李星硕
  17. ★电车难题的n个坑爹变种
  18. 如何把microsoft store里面的软件添加到桌面
  19. 数学建模之规划1——线性规划
  20. 寂静岭:理性与心魔的拔河

热门文章

  1. Flutter实战 | 从 0 搭建「网易云音乐」APP(三、每日推荐、推荐歌单)
  2. 机器学习如何推动数据中心发展?
  3. 内部名称解析设置阿里云私有 DNS 区域,针对于阿里云国际版经验教程
  4. 光的干涉衍射计算机模拟仿真技术,实验报告之仿真(光的干涉与衍射).doc
  5. viola jones人脸检测原理
  6. 网易我的世界服务器配置文件翻译,1.12.2实用拓展配置文件翻译(暂未完成)
  7. 关于gnome-terminal运行脚本,程序停止或者奔溃时终端自动退出问题
  8. 安卓手机怎么设置蓝牙耳机弹窗动画_无线蓝牙耳机~~三代
  9. laravel调用接口展示数据
  10. C#使用POST调用接口