mybatis使用标签为非自增主键(如uuid、数据库序列)生成并绑定主键值,核心是按order="before"或"after"执行指定sql,将结果赋给keyproperty指定的java对象属性;同时支持usegeneratedkeys替代方案。

MyBatis 使用 <selectkey></selectkey> 标签为非自增主键(如 UUID、数据库序列)生成并绑定主键值,核心在于在执行 INSERT 语句前或后,通过指定 SQL 获取主键,并将其赋值给 Java 对象的对应属性。
1. 使用 <selectkey></selectkey> 生成 UUID 并写入对象
适用于主键由应用层生成(如 UUID),且需在 INSERT 前设置主键值。此时 keyProperty 指向 Java 对象字段,order="BEFORE" 表示先执行 selectKey 再执行 insert。
示例(MySQL / PostgreSQL 支持 UUID() 函数):
<insert id="insertUser" parametertype="User"><selectkey keyproperty="id" resulttype="string" order="BEFORE">
SELECT UUID()
</selectkey>
INSERT INTO user (id, name, email) VALUES (#{id}, #{name}, #{email})
</insert>
说明:
- keyProperty="id":将查询结果赋值给 User 对象的 id 字段;
- resultType="string":匹配 UUID 返回类型(String);
- order="BEFORE":确保 INSERT 时 #{id} 已有值。
2. 使用数据库序列(如 Oracle、PostgreSQL)生成主键
对于支持序列的数据库,<selectkey></selectkey> 通常放在 INSERT 之后(order="AFTER"),从序列中取值并回填到对象中。
Oracle 示例:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
<insert id="insertUser" parametertype="User">
INSERT INTO user (id, name, email) VALUES (user_seq.NEXTVAL, #{name}, #{email})
<selectkey keyproperty="id" resulttype="long" order="AFTER">
SELECT user_seq.CURRVAL FROM DUAL
</selectkey></insert>
PostgreSQL 示例(使用 RETURNING 更简洁,但 <selectkey></selectkey> 仍兼容):
<insert id="insertUser" parametertype="User">
INSERT INTO user (id, name, email)
VALUES (nextval('user_seq'), #{name}, #{email})
<selectkey keyproperty="id" resulttype="long" order="AFTER">
SELECT currval('user_seq')
</selectkey></insert>
注意:
- order="AFTER" 表示 INSERT 执行完再查序列当前值;
- 确保序列已存在且权限正确;
- PostgreSQL 中也可用 RETURNING id 直接返回,但需配合 useGeneratedKeys="true" 和 keyColumn/keyProperty(见下文)。
3. 替代方案:useGeneratedKeys + keyColumn(推荐用于支持 RETURNING 的数据库)
对 PostgreSQL、SQL Server、MySQL(含 AUTO_INCREMENT)等支持“生成键”机制的数据库,可不用 <selectkey></selectkey>,改用更简洁的原生方式:
<insert id="insertUser" parametertype="User" usegeneratedkeys="true" keyproperty="id" keycolumn="id">
INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
说明:
- useGeneratedKeys="true" 启用 JDBC 的 getGeneratedKeys();
- keyProperty="id" 指定回填字段;
- keyColumn="id" 明确指定生成键对应的列名(某些驱动需要);
- PostgreSQL 中该方式会自动捕获 RETURNING id 结果,比 <selectkey></selectkey> 更高效安全。
4. 注意事项与常见问题
使用 <selectkey></selectkey> 时需注意以下细节:
- 数据库方言差异大:Oracle 用
CURRVAL,MySQL 用LAST_INSERT_ID(),PostgreSQL 用currval()或RETURNING; -
order必须与执行时机严格匹配:BEFORE 要求 selectKey 返回值可用于 INSERT 参数,AFTER 要求 INSERT 已完成且能获取生成值; - 多线程/高并发下,UUID 方案天然无竞争,序列方案依赖数据库原子性,一般无需额外加锁;
- 实体类主键字段必须有 public setter 方法,否则 MyBatis 无法赋值;
- 若
keyProperty路径较深(如address.id),需确保嵌套对象已初始化,否则抛 NPE。
不复杂但容易忽略:只要选对时机(BEFORE/AFTER)、匹配数据库语法、确保字段可写,<selectkey></selectkey> 就能可靠支撑非自增主键场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










