在 MyBatis 的映射元素 <resultMap> 中,<id> 和 <result> 都用于将查询结果集的列映射到 Java 对象的属性
在 MyBatis 的resultMap中id和result都用于将查询结果集的列映射到 Java 对象的属性但它们的语义和内部处理机制有本质区别。下面从多个维度详细讲解。1.resultMap简介resultMap是 MyBatis 中最重要的映射元素之一用于定义如何将 SQL 查询结果集的列映射到 Java 对象的属性。它支持简单的属性映射result主键标识id关联映射association集合映射collection鉴别器discriminator当结果集包含多表关联时resultMap能够精确控制对象的嵌套结构。2.id的作用id标签用于映射主键列或逻辑上的唯一标识列其核心作用是告诉 MyBatis 该字段是对象的唯一标识。MyBatis 会在内部利用这个标识进行优化2.1 对象复用与缓存在嵌套查询或关联映射如association或collection中如果结果集包含多行数据MyBatis 会根据id映射的值来判断某个对象是否已经创建过如果同一主键值已经实例化了一个对象MyBatis 会复用该对象而不是为每一行都创建一个新的对象实例。这避免了对象重复创建节省内存也保证了对象引用的正确性例如多个结果行引用同一个父对象时父对象只有一个实例。示例假设有user和role两个实体一个用户可能有多个角色。查询结果返回如下user_iduser_namerole_idrole_name1张三1管理员1张三2普通用户如果没有id标识主键MyBatis 可能会创建两个独立的User对象即使它们的user_id相同导致内存浪费且对象引用不一致。有了id columnuser_id propertyid/MyBatis 会在第一次遇到user_id1时创建User对象第二次遇到时直接复用该对象并将角色添加到已有的User对象的角色集合中。2.2 性能优化在延迟加载中MyBatis 需要判断对象是否已被加载过id提供了这个依据。在嵌套查询时避免了重复查询相同主键的关联数据。2.3 与result的区别虽然id和result都完成列到属性的映射但id额外承担了“对象标识”的角色因此映射作用相同都能将列值赋给属性。内部处理不同MyBatis 会将id标记的字段作为对象缓存的键CacheKey的一部分用于判断对象是否已存在。3.result的作用result标签用于映射普通列非主键列仅完成列到属性的值复制不参与对象复用的判断。一个resultMap中可以包含多个result分别对应不同的属性。主键列通常也使用result映射但更推荐使用id。4. 两者的对比特性idresult用途标识主键/唯一键映射普通列是否参与对象复用是否性能影响提升嵌套/关联映射性能无特殊影响使用建议结果集中包含主键列时必须使用用于其他所有列能否同时存在主键列只需一个id不应重复使用result可与其他result共存5. 内部实现机制MyBatis 在执行嵌套查询时会维护一个结果集对象缓存ResultMap级别的CacheKey。当解析一行数据时根据id列的值生成CacheKey。如果该CacheKey已存在则直接从缓存中取出对象并继续映射该行的其他列。如果不存在则创建新对象放入缓存然后映射所有列。若未定义idMyBatis 会回退使用整行的所有列值作为缓存键通过Object.equals这可能导致即使主键相同只要其他列有差异如关联表的数据不同也会被认为是不同的对象。缓存命中率低可能创建大量重复对象。因此为结果集指定主键id是使用 MyBatis 高级映射的最佳实践。6. 示例说明6.1 没有id时的问题xmlresultMap iduserRoleMap typecom.example.User result columnuser_id propertyid/ result columnuser_name propertyname/ collection propertyroles ofTypecom.example.Role result columnrole_id propertyid/ result columnrole_name propertyname/ /collection /resultMap假设查询返回两行数据user_id都是1但role_id不同。由于没有idMyBatis 会为每一行都创建一个新的User对象尽管它们的id相同然后将角色分别添加到两个不同的User对象中。最终结果可能是用户对象被重复创建角色也错误地分散在不同实例中。6.2 使用id修正xmlresultMap iduserRoleMap typecom.example.User id columnuser_id propertyid/ result columnuser_name propertyname/ collection propertyroles ofTypecom.example.Role id columnrole_id propertyid/ result columnrole_name propertyname/ /collection /resultMap此时当 MyBatis 处理第一行时创建User对象并缓存键为user_id1。第二行遇到相同的user_id直接从缓存中取出该User对象然后将第二个角色添加到同一个User的roles集合中。最终得到一个正确的User对象其roles包含两个角色。7. 最佳实践始终为结果集的主键列或唯一标识列使用id标签即使当前映射中没有嵌套对象。这有助于未来扩展也能让 MyBatis 内部优化更高效。避免同时为同一列使用id和result虽然不会报错但会造成冗余且可能引起混淆尤其是在 IDE 的映射提示中。如果表没有主键但结果集中存在逻辑上的唯一标识如联合唯一键也可以使用id映射该组合列可通过id的多个列定义即id columncol1 /和id columncol2 /。8. 总结id和result都是列与属性的映射但id额外承担了“对象标识”的语义用于 MyBatis 内部的缓存和对象复用。在复杂映射尤其是关联查询中正确使用id可以避免重复对象创建保证内存效率和对象引用的正确性。无论是否涉及嵌套为结果集的主键列使用id是一个良好的编码习惯。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2475261.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!