当前位置: 首页 > news >正文

MyBatis主键返回机制解析

关于 MyBatis 主键返回的深入解释

核心问题:信息隔离

数据库和应用程序是两个独立的系统:

  1. 数据库在服务器上执行 INSERT 操作并生成主键
  2. 应用程序在另一个进程或甚至另一台机器上运行
  3. 如果没有明确的机制,应用程序无法自动知道数据库生成了什么值

没有 @Options 或相关配置时的情况

// 假设没有配置主键返回
User user = new User();
user.setName("John");
userMapper.insert(user);// 此时 user.getId() 返回什么?
System.out.println(user.getId()); // 输出: null 或 0

在这种情况下,user 对象中的 id 字段不会被自动填充,因为 MyBatis 不知道需要将生成的主键值回填到对象中。

为什么需要显式配置

MyBatis 需要明确的指令来执行主键回填操作:

  1. useGeneratedKeys=true:告诉 MyBatis 使用 JDBC 的 getGeneratedKeys() 方法获取数据库生成的主键
  2. keyProperty="id":告诉 MyBatis 将获取到的主键值设置到参数对象的哪个属性中
// 使用 @Options 配置主键返回
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO users (name) VALUES (#{name})")
int insertUser(User user);// 使用后
User user = new User();
user.setName("John");
userMapper.insertUser(user);
System.out.println(user.getId()); // 输出: 123 (数据库生成的实际ID)

技术实现原理

当配置了主键返回后,MyBatis 和 JDBC 驱动会协同工作:

  1. MyBatis 通过 JDBC 执行 INSERT 语句
  2. JDBC 驱动调用 statement.getGeneratedKeys() 方法
  3. 数据库返回生成的主键值
  4. MyBatis 根据 keyProperty 配置,将主键值反射设置到参数对象的对应字段中

如果不配置主键返回,如何获取ID?

如果不使用 MyBatis 的主键返回功能,您仍然可以获取生成的主键,但需要额外的工作:

方法一:后续查询(不推荐)

userMapper.insert(user);
// 需要额外查询获取最后插入的ID(不可靠,特别是在高并发环境下)
Long id = userMapper.getLastInsertId();
user.setId(id);

方法二:数据库特定函数(局限性大)

-- 在INSERT语句后直接查询(MySQL示例)
INSERT INTO users (name) VALUES ('John');
SELECT LAST_INSERT_ID();

但这种方法需要执行两条SQL语句,且在高并发环境下可能不可靠。

为什么不能"直接getId提出"

您可能会想:“既然数据库生成了ID,我直接从对象中获取不就行了?”

问题在于:Java 对象和数据库之间没有自动的魔法连接。当您创建一个新的 User 对象时,它的 id 字段是 null(或默认值)。执行 INSERT 操作后,数据库中生成了ID,但这个值不会自动反映到您的 Java 对象中,除非有明确的机制(如 MyBatis 的主键返回功能)将它们连接起来。

总结

情况结果
不配置主键返回user.getId() 返回 null 或初始值,无法获取数据库生成的ID
配置主键返回user.getId() 返回数据库实际生成的ID,可以立即使用

因此,虽然数据库会自动生成自增主键,但应用程序仍然需要明确配置才能获取这个值。MyBatis 的 @Options 注解或其他主键返回配置正是为了搭建这座"桥梁",让应用程序能够方便地获取数据库生成的主键值。


文章转载自:

http://MvnM3eV0.qmncj.cn
http://tUzZSydW.qmncj.cn
http://EJddjplz.qmncj.cn
http://DGGm3SaX.qmncj.cn
http://nmHndZOD.qmncj.cn
http://PxGpxP4v.qmncj.cn
http://t8oDaeSo.qmncj.cn
http://lmQGEYjY.qmncj.cn
http://DYvefmFu.qmncj.cn
http://KDr5zy0V.qmncj.cn
http://gP0jJam9.qmncj.cn
http://iFNLPlxP.qmncj.cn
http://C2OGKNpu.qmncj.cn
http://PoffqOq5.qmncj.cn
http://VAjsj5hU.qmncj.cn
http://pd9mfp4x.qmncj.cn
http://938MoCBT.qmncj.cn
http://jrD1YG8q.qmncj.cn
http://DrhTezon.qmncj.cn
http://kpAe2ip3.qmncj.cn
http://CjJwlZdt.qmncj.cn
http://ddql7omf.qmncj.cn
http://nWTBjfbL.qmncj.cn
http://MtYCEaLX.qmncj.cn
http://SrEPUEy7.qmncj.cn
http://WH98XEnN.qmncj.cn
http://OJKb2C6I.qmncj.cn
http://Qpk3SD3N.qmncj.cn
http://TgcD94MT.qmncj.cn
http://vPpF2RlK.qmncj.cn
http://www.dtcms.com/a/382630.html

相关文章:

  • 压缩和归档 文件传输
  • 定积分常用方法
  • AI Deepseek学习及运用
  • 重塑你的大脑:从理解突触到掌控人生
  • 19、从感知机到神经网络 - 智能的萌芽与进化
  • c++中导出函数调用约定为__stdcall类型函数并指定导出函数名称
  • [工作表控件22] 控件权限设置与字段级安全控制:业务中如何保障数据安全与合理访问
  • (LeetCode 每日一题) 3541. 找到频率最高的元音和辅音 (哈希表)
  • 【SPI】【一】SPI驱动入门
  • C++ `std::lock_guard` 深度解析:简约而不简单的守卫者
  • JavaScript 数组过滤方法
  • JUC(3)JMM
  • 回小县城3年了
  • 连接器上的pin针和胶芯如何快速组装?
  • String、StringBuffer 和 StringBuilder 的区别
  • 测试抽奖系统,设计测试case
  • vue的响应式原理深度解读
  • Python核心技术开发指南(061)——常用魔术方法
  • 简单概述操作系统的发展
  • 从0开始:STM32F103C8T6开发环境搭建与第一个LED闪烁
  • linux C 语言开发 (九) 进程间通讯--管道
  • LinuxC++项目开发日志——高并发内存池(5-page cache框架开发)
  • MATLAB基于组合近似模型和IPSO-GA的全焊接球阀焊接工艺参数优化研究
  • SpringSecurity的应用
  • 算法题(206):方格取数(动态规划)
  • 第十六周周报
  • [硬件电路-193]:双极型晶体管BJT与场效应晶体管FET异同
  • ID3v2的header中的扩展标头(Extended Header),其Size字段如何计算整个ID3的长度?
  • 【51单片机】【protues仿真】基于51单片机的篮球计时计分器系统
  • Linux -- 权限的理解