mabatis-plus用saveBatch,自增的主键id怎么返回来
时间: 2025-07-21 21:02:01 浏览: 3
<think>我们正在讨论MyBatis-Plus的saveBatch方法如何返回自增主键ID。根据引用[1]和引用[3],我们知道在批量插入时,默认情况下使用saveBatch可能无法返回自增主键。但是,引用[1]提到“使用mybatis-plus实现的saveBatch方法是可以返回自增主键的”,所以我们需要了解如何配置才能实现。
关键点:
1. 在MyBatis-Plus中,如果数据库支持自增主键(如MySQL),并且我们正确配置了实体类的主键字段(使用`@TableId(type = IdType.AUTO)`),那么在单条插入时,MyBatis-Plus会自动将生成的主键回填到实体对象中。
2. 对于批量插入(saveBatch),MyBatis-Plus内部实际上是循环执行单条插入(默认情况下),所以理论上每条记录插入后都会回填主键。但是,请注意,MyBatis-Plus的默认批量插入并不是真正的批量(即不是一条SQL插入多条),而是通过事务+循环单条插入实现的,因此每条插入后都会回填主键。
然而,引用[3]提到在分库分表(Sharding Sphere JDBC)环境下,使用saveBatch无法返回主键。这是因为分库分表中间件可能会改写SQL,导致主键无法回填。此外,引用[4]和[5]提到了其他问题,如主键重复或数据库驱动不支持。
因此,我们需要分情况讨论:
情况一:非分库分表环境(普通数据库,如MySQL)
- 配置实体类的主键为自增:`@TableId(type = IdType.AUTO)`
- 使用saveBatch方法后,实体对象列表中的每个对象的主键(id)会被自动回填。
情况二:分库分表环境(使用Sharding Sphere JDBC)
- 根据引用[3],Sharding Sphere JDBC在批量插入时可能会重新组合SQL,导致无法返回自增主键。这是因为在分片环境下,自增主键通常由Sharding Sphere提供(通过其内置的分布式主键生成器),而不是数据库自增。
- 解决方案:在实体类的主键字段上,使用Sharding Sphere的分布式主键生成策略,例如:
`@TableId(type = IdType.ASSIGN_ID)` // 使用雪花算法生成分布式ID
这样,在插入之前,主键就已经生成并设置到实体对象中,不需要数据库返回。
但是,如果用户希望使用数据库自增(在分片环境下不推荐,因为不同分片可能产生重复ID),则可能需要调整Sharding Sphere的配置,或者使用其他方式。
另外,引用[2]提供了一种通过XML手动编写批量插入SQL的方法,并设置`keyProperty`来返回主键。但是,这种方法要求数据库支持批量插入时返回自增主键(例如MySQL的`useGeneratedKeys`支持多行插入)。而达梦数据库(引用[1])可能不支持,所以需要根据数据库类型判断。
总结步骤:
1. 确认数据库是否支持批量插入返回自增主键(如MySQL支持,达梦不支持)。
2. 在非分库分表环境下,使用MyBatis-Plus的saveBatch方法,并确保实体类主键配置为`@TableId(type = IdType.AUTO)`,即可自动回填。
3. 在分库分表环境下,建议使用分布式主键(如IdType.ASSIGN_ID)预先生成主键,这样就不需要数据库返回。
4. 如果数据库不支持批量返回自增主键(如达梦),且必须使用自增主键,则可以考虑使用循环单条插入(saveBatch内部就是循环单条插入,所以应该可以返回主键)或者参考引用[2]中的XML方式(但需要数据库支持)。
注意:MyBatis-Plus的saveBatch方法在3.4.0版本之前是循环单条插入,3.4.0之后默认使用动态SQL批量插入(需要配置`mybatis-plus.global-config.db-config.insert-strategy=batched`),但批量插入方式可能不支持主键回填,具体取决于数据库驱动。
因此,如果使用批量插入方式(非循环单条)且数据库不支持批量返回主键,则无法回填。此时,可以切换回循环单条插入(通过配置`insert-strategy`为`not_batched`)来保证主键回填。
具体配置:
在application.yml中:
```yaml
mybatis-plus:
global-config:
db-config:
insert-strategy: not_batched # 使用循环单条插入,默认为batched(批量插入)
```
但是,循环单条插入性能较低,批量插入性能高但不一定支持主键回填。
所以,最佳实践:
- 对于MySQL:在配置了`IdType.AUTO`后,使用saveBatch(循环单条插入方式)可以回填主键;如果使用批量插入(一条SQL插入多条),则需要设置`useGeneratedKeys`和`keyProperty`,并且MySQL的JDBC驱动支持批量返回自增主键(实际上,MySQL的JDBC驱动在批量插入时只能返回最后一条插入的自增ID,所以无法回填多条记录的所有ID)。因此,对于MySQL,批量插入方式无法回填多个ID,只能使用循环单条插入。
- 对于支持批量返回自增主键的数据库(如某些数据库返回一个ID数组),则可以通过自定义XML实现(如引用[2])并配置`keyProperty`。
结论:
在MyBatis-Plus中,使用saveBatch方法返回自增主键的推荐做法是:
1. 确保实体类主键字段使用`@TableId(type = IdType.AUTO)`
2. 配置MyBatis-Plus使用循环单条插入(默认的批量插入策略为`batched`时,在MySQL下无法回填多个ID,所以需要改为`not_batched`,或者不配置批量插入策略,因为3.4.0之前的版本默认就是循环单条插入)
注意:在3.4.0及之后版本,默认的批量插入策略是`batched`,所以需要显式配置为`not_batched`才能使用循环单条插入,从而回填主键。
因此,步骤:
1. 配置实体类:
@TableId(type = IdType.AUTO)
private Long id;
2. 在配置文件中设置插入策略为循环单条插入(为了兼容性,确保回填主键):
mybatis-plus.global-config.db-config.insert-strategy=not_batched
3. 然后调用saveBatch方法,传入实体列表,插入后每个实体对象的主键字段会被赋值。
注意:如果使用分库分表(ShardingSphere),则不建议使用数据库自增主键,而应使用分布式主键(IdType.ASSIGN_ID)。
参考引用:
[^1]: 达梦数据库不能通过设置useGeneratedKeys为true来支持批量插入返回自增主键,但是使用mybatis-plus实现的saveBatch方法是可以返回自增主键的。
[^2]: 可以通过编写XML批量插入,并设置keyProperty来返回主键(需要数据库支持)。
[^3]: Sharding Sphere JDBC环境下,使用saveBatch无法返回主键,因为SQL被改写。
[^4]: 主键重复问题,可能是因为主键没有正确自增,或者回填失败导致下次插入还是用同样的值。
[^5]: SQLite不支持返回自增主键。
因此,根据用户需求,如果用户使用的是普通数据库(如MySQL),并且配置了循环单条插入,则saveBatch可以返回自增主键。
如果用户使用的是分库分表,建议改用分布式主键生成策略。
如果用户使用的数据库不支持批量返回自增主键(如达梦、SQLite),则可能需要使用循环单条插入(即配置insert-strategy为not_batched)来确保每条插入后回填主键。
最终回答:
我们将按照以下步骤实现MyBatis-Plus的saveBatch方法返回自增主键ID:
1. 实体类主键字段添加注解`@TableId(type = IdType.AUTO)`
2. 配置MyBatis-Plus使用循环单条插入(在application.yml中设置`insert-strategy: not_batched`)
3. 调用saveBatch方法,然后实体列表中的每个对象的主键会被自动填充。
注意:在分库分表环境下,请使用分布式主键(IdType.ASSIGN_ID)代替数据库自增。
下面我们生成相关问题。</think>### MyBatis-Plus saveBatch 返回自增主键 ID 的方法
在 MyBatis-Plus 中,`saveBatch` 方法默认**不会自动回填自增主键 ID**,但可通过以下配置实现:
#### ✅ 正确配置步骤
1. **实体类主键注解配置**
在实体类的主键字段添加注解 `@TableId(type = IdType.AUTO)`:
```java
@Data
public class User {
@TableId(type = IdType.AUTO) // 关键配置
private Long id;
private String name;
}
```
2. **配置插入策略(关键步骤)**
在 `application.yml` 中启用 MyBatis-Plus 的循环单条插入策略:
```yaml
mybatis-plus:
global-config:
db-config:
insert-strategy: not_batched # 关闭批量SQL重写
```
*📌 原理:此配置禁用批量 SQL 重组,改为循环执行单条插入(每条插入后自动回填主键)[^1][^3]。*
3. **调用 saveBatch 方法**
插入后实体列表会自动填充主键:
```java
List<User> userList = Arrays.asList(new User("Tom"), new User("Jerry"));
userService.saveBatch(userList); // 批量插入
// 插入后自动回填ID
userList.forEach(user -> System.out.println(user.getId())); // 输出自增ID
```
---
#### ⚠️ 注意事项
1. **数据库兼容性**
- MySQL/PostgreSQL 等支持 `AUTO_INCREMENT` 的数据库可直接使用
- **达梦数据库**:需手动配置 XML 批量插入(参考引用[1][^1])
- **SQLite**:不支持自增主键回填(需手动生成主键,参考引用[5][^5])
2. **分库分表场景**
使用 ShardingSphere 时:
```java
@TableId(type = IdType.ASSIGN_ID) // 改用分布式ID生成
private Long id;
```
*原因:分片中间件会改写 SQL,导致自增主键失效(参考引用[3][^3])*
3. **主键冲突解决方案**
若遇 `DuplicateKeyException`:
- 检查是否遗漏 `@TableId(type = IdType.AUTO)`
- 确认数据库表主键已设为 `AUTO_INCREMENT`
---
#### 💡 替代方案(XML 手动批量插入)
适用于禁用 SQL 重写的场景:
```xml
<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
INSERT INTO user (name) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.name})
</foreach>
</insert>
```
*📌 需满足:数据库支持多行插入返回自增 ID(如 MySQL 8+)[^2][^4]。*
---
阅读全文
相关推荐



















