🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录
⛳️ 推荐
MyBatis关联关系映射详解
一、关联映射概述
二、一对一(1:1)映射
场景示例
实现方式一:嵌套结果映射(多表连接)
实现方式二:嵌套查询(子查询)
Java实体类示例
三、一对多(1:N)映射
场景示例
实现方式
Java实体类示例
四、多对一(N:1)映射
场景示例
实现方式
Java实体类示例
五、多对多(N:N)映射
场景示例
实现方式
Java实体类示例
六、最佳实践和注意事项
1. 避免N+1查询问题
2. 合理选择映射方式
3. 使用驼峰命名转换
4. 复杂查询的优化
七、总结
MyBatis关联关系映射详解
在实际开发中,数据库表之间通常存在复杂的关联关系。MyBatis通过<resultMap>提供了强大的对象关系映射能力,支持一对一(1:1)、一对多(1:N)、多对一(N:1)和多对多(N:N)四种经典关系的映射。本文将结合代码示例,系统讲解各种关联关系的实现方式。
一、关联映射概述
在关系型数据库中,表与表之间存在三种基本关联关系:
- 一对一(One-to-One):一个表中的每个记录与另一个表中的一个记录相关联
- 一对多/多对一(One-to-Many/Many-to-One):一个表中的一个记录可以与另一个表中的多个记录相关联
- 多对多(Many-to-Many):一个表中的多个记录可以与另一个表中的多个记录相关联
MyBatis实现关联关系映射主要有两种方式:多表连接和子查询。
二、一对一(1:1)映射
场景示例
- 用户和身份证信息
- 班级和班主任
- 用户和用户详情
实现方式一:嵌套结果映射(多表连接)
<!-- 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>实现方式二:嵌套查询(子查询)
<resultMap id="userWithIdCard2" type="User"> <id property="id" column="user_id"/> <result property="username" column="username"/> <!-- 通过执行另一个SQL映射语句来返回预期的复杂类型 --> <association property="idCard" column="card_id" select="com.example.mapper.IdCardMapper.selectById"/> </resultMap> <select id="selectUserWithIdCard2" resultMap="userWithIdCard2"> SELECT * FROM user WHERE user_id = #{id} </select>Java实体类示例
// User.java public class User { private Integer id; private String username; private IdCard idCard; // 一对一关联属性 // getter和setter方法... } // IdCard.java public class IdCard { private Integer id; private String number; // getter和setter方法... }三、一对多(1:N)映射
场景示例
- 一个班级有多个学生
- 一个用户拥有多个角色
- 一个部门有多个员工
实现方式
<!-- UserMapper.xml --> <resultMap id="userWithRoles" type="User"> <id property="id" column="user_id"/> <result property="username" column="username"/> <!-- 一对多关联,使用collection标签 --> <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>Java实体类示例
// User.java public class User { private String id; private String username; private List<Role> roles; // 一对多关联属性 // getter和setter方法... } // Role.java public class Role { private String id; private String name; // getter和setter方法... }四、多对一(N:1)映射
场景示例
- 多个学生属于一个班级
- 多个订单属于一个用户
- 多个项目属于一个公司
实现方式
<!-- StudentMapper.xml --> <resultMap id="studentWithClass" type="Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <!-- 多对一关联,使用association标签 --> <association property="clazz" javaType="Class"> <id property="id" column="class_id"/> <result property="name" column="class_name"/> </association> </resultMap> <select id="selectStudentWithClass" resultMap="studentWithClass"> SELECT s.student_id, s.student_name, c.class_id, c.class_name FROM student s LEFT JOIN class c ON s.class_id = c.class_id WHERE s.student_id = #{id} </select>Java实体类示例
// Student.java public class Student { private Integer id; private String name; private Class clazz; // 多对一关联属性 // getter和setter方法... } // Class.java public class Class { private Integer id; private String name; // getter和setter方法... }五、多对多(N:N)映射
场景示例
- 学生和课程(一个学生可以选修多门课程,一门课程可以被多个学生选修)
- 用户和角色(一个用户可以有多个角色,一个角色可以被多个用户拥有)
实现方式
多对多关系通常通过一个**关联表(中间表)**来实现。
<!-- StudentMapper.xml --> <resultMap id="studentWithCourses" type="Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <!-- 多对多关联,使用collection标签 --> <collection property="courses" ofType="Course"> <id property="id" column="course_id"/> <result property="name" column="course_name"/> </collection> </resultMap> <select id="selectStudentWithCourses" resultMap="studentWithCourses"> SELECT s.student_id, s.student_name, c.course_id, c.course_name FROM student s LEFT JOIN student_course sc ON s.student_id = sc.student_id LEFT JOIN course c ON sc.course_id = c.course_id WHERE s.student_id = #{id} </select>Java实体类示例
// Student.java public class Student { private Integer id; private String name; private List<Course> courses; // 多对多关联属性 // getter和setter方法... } // Course.java public class Course { private Integer id; private String name; // getter和setter方法... }六、最佳实践和注意事项
1. 避免N+1查询问题
在使用嵌套查询(子查询)方式时,容易产生N+1查询问题。例如,查询10个用户及其角色,会先执行1次查询用户,然后对每个用户再执行1次查询角色的SQL,总共11次查询。
解决方案:
- 优先使用嵌套结果映射(多表连接)方式
- 使用MyBatis的延迟加载功能
- 合理使用缓存
2. 合理选择映射方式
- 嵌套结果映射(多表连接):适合数据量不大、关联表不多的场景,只需一次SQL查询
- 嵌套查询(子查询):适合数据量大、需要延迟加载的场景,但要注意N+1问题
3. 使用驼峰命名转换
在MyBatis配置文件中开启驼峰命名转换,可以简化映射配置:
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>4. 复杂查询的优化
对于复杂的关联查询,可以考虑:
- 使用数据库视图简化查询
- 使用MyBatis的动态SQL功能
- 合理设计数据库索引
- 使用分页查询减少数据传输量
七、总结
MyBatis的关联映射功能为开发者提供了强大的数据访问层支持。通过<resultMap>、<association>和<collection>标签,可以灵活地处理各种复杂的对象关系映射。在实际开发中,应根据具体业务场景选择合适的映射方式,并注意性能优化,以构建高效、稳定的数据访问层。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙