一场不期而遇的面试杀局
故事要从我那位程序员朋友老杜讲起。
那天,他刚面完一家中型互联网公司,跟我在楼下的奶茶店见面,手里还拎着一杯没喝几口的多肉葡萄,坐下就开始诉苦:“小米啊,MyBatis 的主键回填,面试官怎么能问得这么细?”
我好奇地挑了挑眉:“就主键那点事,问出花来了吗?”
“花不花我不知道,反正我答得是稀碎。”老杜一脸郁闷,“我以为 useGeneratedKeys=true 就完事了,结果他让我说出几种方式,还要说出适用场景,还要知道什么数据库支持……”
我一听,这不正好就是你找我喝奶茶的理由吗?于是,我轻轻掀起奶茶盖,一边搅拌冰块,一边给他讲起了“主键回填”的那些事儿。
主键回填,到底是什么?
在说“怎么获取”之前,我们得搞清楚“为什么要获取”。
在我们插入一条数据,比如一条用户记录时,往往这个用户的主键 ID 是数据库自动生成的(通常是自增的)。这时候,我们插完数据之后,业务层还得用这个主键去干点别的事,比如:
- 插完用户,还得插他的角色,需要用这个用户 ID;
- 插完订单,还得插订单明细;
- 插完文章,还得记录日志。
所以我们必须得知道:刚才插入的那条数据的主键,到底是个啥?
这就到了 MyBatis 回填主键 的核心问题。
方法一:useGeneratedKeys + keyProperty(推荐用法)
这是最常见、最“自动化”的方式,配置简单,效率也高。
只需要在 insert 标签里加上:
然后你的 User 实体里要有 id 这个字段,MyBatis 就会在执行完插入之后自动把生成的主键设置到 user.id 上。
使用前提:
- 数据库支持自增主键(比如 MySQL、SQL Server);
- JDBC 驱动支持返回主键(现代 JDBC 都支持);
- 配置没写错(是 keyProperty,不是 keyColumn)。
易错点:
有朋友把 keyProperty 写错成 keyColumn,导致拿不到主键,一通 Debug,结果是写错了属性名。
方法二:selectKey 标签(适用于 Oracle、PostgreSQL 等)
如果你用的是 Oracle、PostgreSQL 这类不支持 JDBC 自增主键返回的数据库,就需要手动执行一条 SQL,把主键查出来。
解释一下参数:
- keyProperty:回填到 Java 对象的哪个属性;
- resultType:返回值类型;
- order:在 insert 前执行(BEFORE)还是后执行(AFTER);
- SQL 内容:从序列里拿一个主键。
注意点:
- 如果是 order="BEFORE",你要确保后续 insert 用了 #{id};
- 如果是 order="AFTER",说明你让数据库自己生成主键(比如触发器),那你就不要自己赋值了。
方法三:Mapper 注解方式
如果你用的是注解版的 Mapper 接口,也能支持主键回填:
简洁、明了、推荐使用。但有一点:
- 一定要确认你用的数据库支持 getGeneratedKeys() 方法!
实战中的几个问题
问题一:插入成功,但主键没回填?
大概率是因为你没写 keyProperty,或者实体类字段名和 keyProperty 不一致。MyBatis 默认不会帮你“猜”。
问题二:用 Oracle 报错?
Oracle 不支持 useGeneratedKeys=true,必须得用 selectKey 配合序列。
问题三:Mapper 多参数时,主键回填不到对象上?
这个就比较坑了。比如你传了两个参数,一个是 user 对象,一个是其他值:
这时候你要写:
因为 MyBatis 会把参数包装成一个 Map,真正的对象是 user.id,而不是直接 id。
数据库支持情况一览表
小米的经验小贴士
作为一个用过 N 年 MyBatis 的老兵,我再分享一些面试中经常踩坑的点:
- 问 useGeneratedKeys 原理:其实底层是调用 JDBC 的 getGeneratedKeys() 方法;
- 问多条插入如何回填? 一般不支持返回多个主键,可以考虑分批插;
- 问为什么用 keyProperty 而不是 keyColumn? keyProperty 是 Java 对象字段,keyColumn 是数据库字段。
面试最后一分钟,老杜逆风翻盘!
那天,我奶茶讲完,老杜恍然大悟。
第二轮面试他又遇到了这个问题,这次他笑着说:
“MySQL 用 useGeneratedKeys 就行,Oracle 用 selectKey 搞个序列,注解版也能回填,重点是搞清楚你要的主键从哪来、怎么拿、填到哪。”
当场把面试官整不会了。
后来他告诉我,他拿到了 offer,面试官评价是:“你是我今天面过唯一一个能讲清主键回填机制的人。”
END
MyBatis 虽然是老技术,但基础越扎实,越能在面试场上脱颖而出。如果你也有 MyBatis 使用问题或者面试卡壳的地方,欢迎私信我,咱们一起研究研究~
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!