mybatis批量插入返回主键ID总是返回最后一个插入的主键ID之解决方式
项目框架是spring cloud全家桶,引入的mybatis版本如下:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
Dao接口
int batchInsertCameras(@Param("list") List<Camera> cameras);
Xml文件
<insert id="batchInsertCameras" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into camera (camera_type,camera_name)
values
<foreach collection="list" item="c" separator=",">
(#{c.cameraType},#{c.cameraName})
</foreach>
</insert>
- useGeneratedKeys:对于支持自动生成记录主键的数据库,如:MySQL,SQL Server,此时设置useGeneratedKeys参数值为true,在执行添加记录之后可以获取到数据库自动生成的主键ID
- keyColumn:指定数据库主键
- keyProperty:指定在Java实体类中对应的主键
代码执行过程(截取了片段)-出问题的所在地!
// 初始化:批量添加三个相机
int number = 3;
// 通过基础信息构建Camera类
Camera camera = constructCamera(cameraDTO);
// 构建批量插入所需的Camera集合
List<Camera> cameraList = new ArrayList<>(number);
for (int i = 0; i < number; i++) {
// ******************!!!注意就是这一步,导致问题的出现,后续说明!!!!******************
cameraList.add(camera);
}
// 开始批量插入
int insertRows = cameraDao.batchInsertCameras(cameraList);
log.info("批量添加相机成功,添加的数据为:{}", cameraList);
现象1
传入3个对象的集合进行批量插入,主键ID确实能够将入参赋值成功,但是只返回最后一个成功插入的id 并且赋值给了每记录 ,也就是入参的集合中所有的对象ID都赋值成了最后一个成功插入的ID。官方也是支持批量插入返回主键的啊,为何会出现这种情况呢,妈的思来想去搞了两个小时,调参数啥的,按照网上的方式替换mybatis版本或者加注释啥的,通通不管用。我暂时放弃了,第二天再来分析突然醒悟了,于是写下这篇博客记录一下。
分析
- 通过mybatis底层打断点分析修正。mybatis对主键赋值的操作位置:org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator#processBatch
- 根据第一步打了几次断点,内部是循环对集合的每个对象进行主键赋值,发现在第一次赋值的时候,就将所有对象的主键都赋值了,而后的每一次循环赋值,都覆盖了每个对象的主键赋值。
- 由第二点我就感觉难不成都是用的同一个对象?操作一个就改变了所有。所以我回头看代码构建插入的入参集合的地方。
- 果然!在构建入参集合处,往集合里面add的都是同一个对象,这就导致第2步的问题!
- 修正入参集合里面的对象,都为不同对象即可!
代码修正后
// 初始化:批量添加三个相机
int number = 3;
// 通过基础信息构建Camera类
Camera camera = constructCamera(cameraDTO);
// 构建批量插入所需的Camera集合
List<Camera> cameraList = new ArrayList<>(number);
for (int i = 0; i < number; i++) {
// ******************!!!这里是较上次唯一变动的地方!!!!******************
Camera cameraNew = new Camera();
BeanUtils.copyProperties(camera, cameraNew);
cameraList.add(couGet);
}
// 开始批量插入
int insertRows = cameraDao.batchInsertCameras(cameraList);
log.info("批量添加相机成功,添加的数据为:{}", cameraList);
结果
成功对每个对象的主键ID赋值,并且赋值正确!直接通过入参的每个对象.getId()就可以获取。