MyBatis 关联映射详解:1:1、1:N、N:1 与 N:N 实现方式

简介: 本文详解 MyBatis 中 resultMap 的四种关联映射:一对一、一对多、多对一和多对多,结合代码示例讲解实现方式与最佳实践,助你掌握复杂对象关系的数据映射技巧。

在实际开发中,数据库表之间通常存在复杂的关联关系。MyBatis 通过 <resultMap> 提供了强大的对象关系映射能力,支持 一对一(1:1)一对多(1:N)多对一(N:1)多对多(N:N) 四种经典关系的映射。本文将结合代码示例,逐一讲解其实现方式。

一、一对一(1:1)映射

场景:一个用户对应一个身份证信息(User ↔ IdCard)。

当 Java 对象属性名与数据库字段名不一致(如字段为 user_id,属性为 id),或需要显式控制映射逻辑时,应使用 <resultMap>

<!-- UserMapper.xml -->
<resultMap id="userWithIdCard" type="User">
  <id property="id" column="user_id"/>
  <result property="username" column="username"/>
  <!-- 一对一关联 -->
  <association property="idCard" javaType="IdCard">
    <id property="id" column="card_id"/>
    <result property="number" column="card_number"/>
  </association>
</resultMap>
<select id="selectUserWithIdCard" resultMap="userWithIdCard">
  SELECT u.user_id, u.username, c.card_id, c.card_number
  FROM user u
  LEFT JOIN id_card c ON u.user_id = c.user_id
  WHERE u.user_id = #{id}
</select>

说明

  • 使用 <association> 标签映射“一”的对象;
  • 若字段与属性名一致(且开启驼峰命名),可直接用 resultType,无需 resultMap

二、一对多(1:N)映射

场景:一个用户拥有多个角色(User → List)。

在“一”的一方(User)中定义集合属性,并使用 <collection> 标签映射。

// User.java
public class User {
  private String id;
  private String username;
  private List<Role> roles; // 一对多
  // getter/setter...
}
<!-- UserMapper.xml -->
<resultMap id="userWithRoles" type="User">
  <id property="id" column="user_id"/>
  <result property="username" column="username"/>
  <!-- 一对多 -->
  <collection property="roles" ofType="Role">
    <id property="id" column="role_id"/>
    <result property="name" column="role_name"/>
  </collection>
</resultMap>
<select id="selectUserWithRoles" resultMap="userWithRoles">
  SELECT u.user_id, u.username, r.role_id, r.role_name
  FROM user u
  LEFT JOIN user_role ur ON u.user_id = ur.user_id
  LEFT JOIN role r ON ur.role_id = r.role_id
  WHERE u.user_id = #{id}
</select>

📌 查询结果示例:

{
  "id": "1003",
  "username": "小波",
  "roles": [
    {"id": "1", "name": "开发"},
    {"id": "2", "name": "TL"}
  ]
}

关键点

  • 使用 ofType 指定集合中元素的类型;
  • SQL 需通过 JOIN 查询出所有关联数据,MyBatis 会自动按主对象分组聚合。

三、多对一(N:1)映射

场景:多篇博客属于同一个作者(Blog → Author)。

在“多”的一方(Blog)中引用“一”的对象(Author),使用 <association>

<!-- BlogMapper.xml -->
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id"/>
  <result property="title" column="blog_title"/>
  <!-- 多对一:每篇博客关联一个作者 -->
  <association property="author" column="author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>
<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</resultMap>
<select id="selectBlogWithAuthor" resultMap="blogResult">
  SELECT b.blog_id, b.blog_title, a.author_id, a.author_username
  FROM blog b
  LEFT JOIN author a ON b.author_id = a.author_id
  WHERE b.blog_id = #{id}
</select>

两种写法

  1. 引用外部 resultMap(如上)——推荐,复用性强;
  2. 内联定义 <association> 内部字段(适用于简单场景):
<association property="author" javaType="Author">
  <id column="author_id" property="id"/>
  <result column="author_username" property="username"/>
</association>

四、多对多(N:N)映射

场景:用户与部门互相关联(User ↔ Dept),通过中间表 user_dept 实现。

由于 MyBatis 不直接支持 N:N 自动映射,需借助中间实体类两次查询实现。常用做法是:

  1. 在 User 中定义 List<Dept>
  2. 在 Dept 中定义 List<User>
  3. 通过中间表 JOIN 查询,利用 <collection> 聚合。
// User.java
public class User {
  private String id;
  private String name;
  private List<Dept> depts; // 多对多
}
<!-- UserMapper.xml -->
<resultMap id="userWithDepts" type="User">
  <id property="id" column="user_id"/>
  <result property="name" column="user_name"/>
  <collection property="depts" ofType="Dept">
    <id property="id" column="dept_id"/>
    <result property="name" column="dept_name"/>
  </collection>
</resultMap>
<select id="selectUserWithDepts" resultMap="userWithDepts">
  SELECT u.user_id, u.user_name, d.dept_id, d.dept_name
  FROM user u
  LEFT JOIN user_dept ud ON u.user_id = ud.user_id
  LEFT JOIN dept d ON ud.dept_id = d.dept_id
  WHERE u.user_id = #{id}
</select>

⚠️ 注意

  • 多对多本质是 两个一对多 的组合;
  • 若关联数据量大,建议分步查询(先查主对象,再根据 ID 批量查关联对象),避免笛卡尔积膨胀。

总结

关系类型 Java 属性 XML 标签 说明
一对一(1:1) 单个对象 <association> 如 User → IdCard
一对多(1:N) List<T> <collection> 如 User → List
多对一(N:1) 单个对象 <association> 如 Blog → Author
多对多(N:N) List<T> <collection> 通过中间表实现

合理使用 <resultMap><association><collection>,可以高效完成复杂对象关系的映射,让 MyBatis 成为你数据层的强大助力。


相关文章
|
2月前
|
人工智能 监控 API
Claude Code终于有仪表盘了:3条命令装个HUD,上下文用了多少一眼就知道
老金我最近用Claude Code,遇到一个特别烦的事。 写着写着,突然蹦出来一句"context window is getting full"。 然后AI就开始犯傻了——回答变短、逻辑变乱、之前说好的方案全忘了。 每次遇到这种情况,老金我都想骂人。 问题出在哪? Claude Code的终端界面,压根看不到上下文用了多少。 你只能输入 /context手动查,但谁写代码的时候
8522 8
|
3月前
|
人工智能 自然语言处理 安全
Claude Code 插件登陆 VS Code:开发者迎来 AI 编程新利器
Anthropic正式发布Claude Code——VS Code官方插件,支持多语言智能补全、代码解释、错误诊断与安全重构。隐私优先、长上下文(200K tokens)处理能力强,显著优于Copilot的可解释性与代码质量,已获开发者广泛好评。(239字)
7064 6
|
7月前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
4258 58
|
5月前
|
运维 安全 Linux
Linux网络telnet命令详解(小白也能轻松掌握的远程连接与端口测试指南)
本文介绍Linux中telnet命令的使用方法,重点讲解如何通过telnet测试网络端口连通性。尽管telnet因明文传输已不推荐用于远程登录,但在排查服务状态、验证端口开放等方面仍具实用价值。教程涵盖安装、基本语法、实战示例及安全建议,适合初学者快速掌握这一轻量级网络调试工具。
|
Java 数据库连接 数据库
Spring Boot与MyBatis的集成应用
Spring Boot与MyBatis的集成应用
|
SQL Java 数据库连接
详解Mybatis之自动映射 & 自定义映射问题(上)
详解Mybatis之自动映射 & 自定义映射问题(上)
|
Java 数据库连接 mybatis
Mybatis基于注解的一对一和一对多查询
Mybatis基于注解的一对一和一对多查询
236 0
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
4942 2
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用

热门文章

最新文章

下一篇
开通oss服务