MyBatis主键返回:必须显式配置
关于主键返回的澄清
核心结论
如果不显式配置主键返回(如使用 @Options
或 XML 中的 useGeneratedKeys
),即使数据库成功生成了自增主键,您的 Java 对象中的 ID 字段也会保持为 null
(或原始值)。
详细解释
1. 数据库 vs 应用程序:两个独立的世界
- 数据库:成功插入记录,生成自增 ID(例如 123)
- 应用程序:有一个
User
对象,其id
字段值为null
如果没有明确的机制将它们连接起来,数据库中的 ID 值不会自动反映到您的 Java 对象中。
2. 代码示例对比
情况一:没有配置主键返回
// 假设 UserMapper 中没有配置主键返回
User user = new User();
user.setName("John Doe");
user.setEmail("john@example.com");// 执行插入
userMapper.insert(user); // 数据库成功生成ID=123// 检查Java对象中的ID
System.out.println(user.getId()); // 输出: null 或 0
// 您无法获取到数据库生成的真实ID
情况二:配置了主键返回
// 在Mapper中配置了主键返回
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
int insert(User user);// 执行插入
User user = new User();
user.setName("John Doe");
user.setEmail("john@example.com");
userMapper.insert(user); // 数据库成功生成ID=123// 检查Java对象中的ID
System.out.println(user.getId()); // 输出: 123
// MyBatis自动将数据库生成的ID回填到对象中
3. 为什么需要显式配置?
主键返回不是自动进行的,因为:
- 性能考虑:不是所有插入操作都需要返回主键
- 灵活性:有些表可能没有自增主键,或者使用其他主键生成策略
- 明确性:让开发者明确知道何时需要这个功能
4. 技术实现原理
当您配置了主键返回后,MyBatis 底层会:
- 通过 JDBC 执行 INSERT 语句
- 使用
Statement.getGeneratedKeys()
方法请求数据库返回生成的主键 - 通过反射将返回的主键值设置到您指定的对象属性中
总结
- ✅ 数据库会生成自增ID:这是真的
- ✅ Java 对象初始 ID 为 null:这也是真的
- ❌ 数据库的ID会自动反映到Java对象中:这是错误的,除非显式配置
如果您需要在插入后立即使用生成的主键,必须显式配置主键返回机制。否则,您将无法从 Java 对象中获取数据库生成的真实 ID 值。
这就是为什么 MyBatis 提供了 @Options(useGeneratedKeys = true)
、useGeneratedKeys="true"
和 <selectKey>
等机制的原因 - 它们搭建了数据库和应用程序之间的"桥梁",让生成的主键值能够返回到您的对象中。