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版本或者加注释啥的,通通不管用。我暂时放弃了,第二天再来分析突然醒悟了,于是写下这篇博客记录一下。

分析

  1. 通过mybatis底层打断点分析修正。mybatis对主键赋值的操作位置:org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator#processBatch
  2. 根据第一步打了几次断点,内部是循环对集合的每个对象进行主键赋值,发现在第一次赋值的时候,就将所有对象的主键都赋值了,而后的每一次循环赋值,都覆盖了每个对象的主键赋值。
  3. 由第二点我就感觉难不成都是用的同一个对象?操作一个就改变了所有。所以我回头看代码构建插入的入参集合的地方。
  4. 果然!在构建入参集合处,往集合里面add的都是同一个对象,这就导致第2步的问题!
  5. 修正入参集合里面的对象,都为不同对象即可!

代码修正后

// 初始化:批量添加三个相机
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()就可以获取。

参考Mybatis赋值主键ID的时序图

posted @ 2020-12-30 14:41  惊叫唤  阅读(2278)  评论(1编辑  收藏  举报