在 MyBatis 中使用 useGeneratedKeys="true"
获取新插入记录的自增 ID 值,可通过以下步骤实现:
在插入语句的
标签中设置:
xml
复制
下载
运行
INSERT INTO user(name, email) VALUES (#{name}, #{email})
useGeneratedKeys="true"
:启用数据库生成的主键(如自增 ID)。
keyProperty="id"
:将生成的主键值赋给参数对象(如 User
对象)的 id
属性。
确保实体类有对应的属性(与 keyProperty
一致):
java
复制
下载
public class User { private Long id; // 属性名必须与 keyProperty 匹配 private String name; private String email; // Getter & Setter }
插入后,自动填充的 ID 会直接赋给传入的实体对象:
java
复制
下载
User newUser = new User(); newUser.setName("John"); newUser.setEmail("[email protected]"); // 执行插入(返回的是影响行数,非 ID) int rows = userMapper.insertUser(newUser); // 插入后,自增 ID 已注入 newUser 的 id 属性 Long newId = newUser.getId(); // ✅ 直接获取 System.out.println("新记录的 ID:" + newId);
keyProperty
必须匹配实体属性名
如实体属性为 userId
,则需配置 keyProperty="userId"
。
支持批量插入(MyBatis 3.3.1+)
配置 keyProperty
为集合元素的属性:
xml
复制
下载
运行
INSERT INTO user(name) VALUES (#{user.name})
调用后,每个对象的 id
都会被赋值:
java
复制
下载
Listusers = Arrays.asList(new User("A"), new User("B")); userMapper.insertUsers(users); users.forEach(u -> System.out.println(u.getId())); // 输出所有新 ID
数据库兼容性
MySQL/SQL Server:直接支持 useGeneratedKeys
。
Oracle:需用
配合序列(非本方案范畴)。
获取值为 null
?
检查 keyProperty
是否与实体属性名一致,或数据库是否真的生成了自增 ID。
批量插入无效?
确保 MyBatis 版本 ≥ 3.3.1,且 keyProperty
指向集合元素的属性(如 id
)。
通过此方案,插入后无需额外查询,ID 值直接注入对象属性,高效简洁。
在 MyBatis 中,keyProperty
可以指定为参数对象中的任意属性路径(包括嵌套对象或 Map 的键值),不一定必须是主实体对象的属性。以下是几种灵活用法:
若参数是一个包含 ID 容器的复合对象:
java
复制
下载
public class InsertParam { private User user; private Long generatedId; // 专门接收 ID 的属性 // Getter & Setter }
Mapper XML 配置:
xml
复制
下载
运行
INSERT INTO user(name) VALUES (#{user.name})
插入后获取:
java
复制
下载
InsertParam param = new InsertParam(); param.setUser(new User("Alice")); userMapper.insertUser(param); Long newId = param.getGeneratedId(); // ✅ 从专用属性获取
Map
参数接收直接通过 Map 传递参数并接收 ID:
xml
复制
下载
运行
INSERT INTO user(name) VALUES (#{name})
Java 调用:
java
复制
下载
Mapparams = new HashMap<>(); params.put("name", "Bob"); userMapper.insertUser(params); Long newId = (Long) params.get("resultId"); // ✅ 从 Map 获取
@Param
)当方法有多个参数时,用 @Param
指定命名空间:
java
复制
下载
int insertUser( @Param("user") User user, @Param("idHolder") MapidHolder // 专门存 ID 的 Map );
Mapper XML 配置:
xml
复制
下载
运行
INSERT INTO user(name) VALUES (#{user.name})
插入后获取:
java
复制
下载
MapidHolder = new HashMap<>(); User user = new User("Charlie"); userMapper.insertUser(user, idHolder); Long newId = idHolder.get("id"); // ✅ 从独立 Map 获取
路径匹配原则
keyProperty
的值是 OGNL 表达式,需严格匹配参数对象的属性路径:
单参数:直接写属性名(如 generatedId
)
多参数:用 @Param
别名前缀(如 idHolder.id
)
批量插入场景
批量操作时 keyProperty
需指向集合元素的属性(不支持外部容器):
xml
复制
下载
运行
INSERT INTO user(name) VALUES (#{item.name})
常见问题
属性未注入? 检查 keyProperty
路径是否存在 setter 方法
返回 null
? 确保数据库自增 ID 已生效(如 MySQL 的 AUTO_INCREMENT
)
专用 ID 容器:推荐用独立 Map
或 DTO 属性接收 ID,避免污染实体对象
明确路径:多参数时用 @Param
定义清晰命名空间(如 keyProperty="holder.id"
)
事务安全:插入后立即从参数对象中获取 ID,确保在同一事务内
当 Mapper 方法有多个参数时,MyBatis 无法确定将生成的自增 ID 注入到哪个参数中。以下是详细解决方案:
复制
下载
Cause: org.apache.ibatis.executor.ExecutorException: Could not determine which parameter to assign generated keys to. Note that when there are multiple parameters, 'keyProperty' must include the parameter name
当 Mapper 方法有多个参数时,必须使用 参数名前缀 明确指定注入位置
您当前配置的 keyProperty="generatedId"
缺少参数名前缀
MyBatis 找到的可用参数:[generatedId, ckDetailId, param1, param2]
@Param
注解明确命名参数java
复制
下载
// Mapper 接口方法 int insertRecord( @Param("data") Mapdata, // 数据参数 @Param("idHolder") Map idHolder // 专门接收ID的参数 );
xml
复制
下载
运行
INSERT INTO your_table(...) VALUES (#{data.field1}, #{data.field2})
xml
复制
下载
运行
...
参数索引从1开始:
param1
=第一个参数,param2
=第二个参数
java
复制
下载
public interface YourMapper { int insertRecord( @Param("detail") YourEntity entity, // 实体参数 @Param("idHolder") Mapholder // ID容器参数 ); }
xml
复制
下载
运行
INSERT INTO your_table(name, ck_detail_id) VALUES (#{detail.name}, #{detail.ckDetailId})
java
复制
下载
// 准备参数 YourEntity entity = new YourEntity("test", 1001); MapidHolder = new HashMap<>(); // 专门接收ID // 执行插入 mapper.insertRecord(entity, idHolder); // 获取自增ID (注意键名与XML中一致) Long newId = idHolder.get("generatedId"); System.out.println("Generated ID: " + newId);
前缀必须匹配 @Param
值
keyProperty="idHolder.generatedId"
对应:
idHolder
→ @Param("idHolder")
generatedId
→ Map中的键名
Map 接收 vs 对象属性
xml
复制
下载
运行
keyProperty="detail.id" keyProperty="idHolder.generatedId"
批量插入特殊处理
批量操作时仍需注入到集合元素内:
xml
复制
下载
运行
INSERT ...
错误现象 | 解决方案 |
---|---|
返回null |
检查数据库自增列是否生效 |
报Invalid bound statement |
检查keyProperty 前缀是否匹配@Param 值 |
批量插入ID未注入 | 确保keyProperty 指向集合元素的属性 |
Oracle数据库不生效 | 需使用 替代 |
建议:对多参数场景始终使用
@Param
+ 前缀的keyProperty
,避免依赖paramN
隐式命名