項目框架是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()就可以獲取。