MyBatis 主键回填返回 1 的真相与避坑指南
在使用 MyBatis 执行插入操作时,发现返回值一直是 1,这是正常的受影响行数。若需获取数据库自增主键,应利用主键回填功能,将生成的 ID 直接注入到传入的实体对象中。本文详解两种主流配置方式及常见的参数注解陷阱。
为什么 insert 返回值是 1?
在 Java 代码中调用 int rows = userDao.insert(user);,如果返回值固定为 1,这并不代表程序出错。1 代表 SQL 执行成功且影响了 1 行数据。真正的主键 ID 需要通过“主键回填”机制,由 MyBatis 写入到你传入的 user 对象属性中。
第 1 步:确保实体对象包含对应属性
你的 Java 实体类(POJO)必须包含与数据库表字段名一致的属性(例如 private Long id;),并提供 getter 和 setter 方法。这是后续赋值的基础。
第 2 步:配置 XML 映射文件实现回填
在 Mapper.xml 的 <insert> 标签中,通过以下两种方式之一启用主键回传:
第 N 步:推荐方式 —— 使用 useGeneratedKeys(简单高效)
这是最常用的配置,适用于 MySQL、Oracle 等支持自动生成 Key 的数据库。
- 目的:告知 MyBatis 使用数据库原生的 getKey 方法获取 ID。
- 配置位置:
<insert>标签上。 - 关键参数:
useGeneratedKeys="true":开启回写。keyProperty="id":指定将 ID 赋给实体对象的哪个属性。
图示:MyBatis XML 中使用 useGeneratedKeys 的配置示例
完整代码示例:
<insert id="addUser" parameterType="blog.model.User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
执行结果判断:
// 执行插入,返回值为影响行数(通常是1)
int rows = userService.addUser(user);
// 此时,user.getId() 已经被 MyBatis 自动注入了刚刚生成的数据库主键
Long generatedId = user.getId();
备选方式 —— 使用 selectKey(灵活控制时序)
selectKey 节点允许更精细地控制主键生成的时机。它可以在 SQL 执行前(BEFORE)或执行后(AFTER)运行一段 SQL 来获取 Key。
图示:MyBatis XML 中使用 selectKey 的配置示例
- 配置位置:嵌套在
<insert>标签内部。 - 关键参数:
keyProperty:目标属性。order="AFTER":通常用于自增主键,意味着在执行完 Insert 语句后查询最后ID。resultType:返回值类型,如INTEGER或LONG。
<insert id="addUser" parameterType="blog.model.User">
<selectKey keyProperty="id" order="AFTER" resultType="long">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
避坑指南:千万不要随意使用 @Param
在 Service 层或 Dao 接口定义中,如果你传递单个对象参数却使用了 @Param 注解,会导致主键回填失效。这是一个非常经典的踩坑点。
// ✅ 正确:直接传递对象,MyBatis 能够识别并使用 keyProperty
void insertBook(InsertBook insertBook);
// ❌ 错误:使用 @Param 包装后,对象被包裹在一个 Map 中,
// MyBatis 找不到直接的 keyProperty 对应的根对象,导致回填失败。
void insertBook(@Param("ib") InsertBook insertBook);
原因分析:当使用 @Param("xxx") 时,MyBatis 会将参数包装成一个键值对集合。即使你的入参只有一个对象,MyBatis 也会尝试从名为 xxx 的对象中查找 keyProperty,而不是直接从该对象本身查找,从而造成 getId() 返回 null。
总结
MyBatis insert 返回 1 是正常的行为逻辑。要获取自增主键,核心在于 useGeneratedKeys="true" 与 keyProperty 的正确配置,并确保传入的是裸对象而非被 @Param 包裹的数据结构。掌握这些细节,即可轻松解决主键回传的疑难杂症。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









