mybatis关系映射
以下是对 MyBatis 中关系映射更详细的解答:
1. 一对一 (One-to-One) 关系映射
嵌套结果映射(XML 方式):
resultMap
元素:resultMap
是核心元素,用于定义如何将查询结果映射到 Java 对象。id
属性为结果映射提供唯一标识符,方便在select
语句中引用。type
属性指定结果映射对应的 Java 类型。
1 2 3 4 5 6 7 8 9
<resultMap id="userResultMap" type="com.example.User"> <id property="id" column="user_id"/> <result property="name" column="user_name"/> <association property="address" javaType="com.example.Address"> <id property="id" column="address_id"/> <result property="street" column="street"/> <result property="city" column="city"/> </association> </resultMap>
<id>
元素:用于映射主键,有助于 MyBatis 进行对象的唯一性识别。<result>
元素:映射非主键列到对象的属性。<association>
元素:用于处理一对一关系,将另一个对象(在此为Address
)映射到User
对象的address
属性。property
属性指定 Java 对象中的属性名。javaType
属性指定关联对象的 Java 类型。
select
语句:- 在
select
语句中使用resultMap
而不是resultType
来引用结果映射。
1 2 3 4 5 6 7
<select id="getUserById" resultMap="userResultMap"> SELECT u.id as user_id, u.name as user_name, a.id as address_id, a.street, a.city FROM users u JOIN addresses a ON u.address_id = a.id WHERE u.id = #{id} </select>
- 这里使用了表连接将
users
表和addresses
表关联,通过ON
子句建立关系。
- 在
使用 @One
注解(Java 接口方式):
Java 类:
1 2 3 4 5 6 7
public class User { private int id; private String name; @One(select = "com.example.AddressMapper.getAddressById", fetch = FetchType.EAGER) private Address address; // Getter 和 Setter 方法 }
@One
注解:select
属性指定一个全限定的 SQL 映射语句的名称,该语句将返回关联对象(在此为Address
)。fetch
属性指定加载策略,FetchType.EAGER
表示立即加载,FetchType.LAZY
表示延迟加载。
2. 一对多 (One-to-Many) 关系映射
嵌套结果映射(XML 方式):
resultMap
元素:1 2 3 4 5 6 7 8
<resultMap id="departmentResultMap" type="com.example.Department"> <id property="id" column="department_id"/> <result property="name" column="department_name"/> <collection property="employees" ofType="com.example.Employee"> <id property="id" column="employee_id"/> <result property="name" column="employee_name"/> </collection> </resultMap>
<collection>
元素:用于处理一对多关系,将多个对象(在此为Employee
)映射到Department
对象的employees
属性。property
属性指定 Java 对象中的属性名。ofType
属性指定集合中元素的 Java 类型。
select
语句:1 2 3 4 5 6 7
<select id="getDepartmentById" resultMap="departmentResultMap"> SELECT d.id as department_id, d.name as department_name, e.id as employee_id, e.name as employee_name FROM departments d LEFT JOIN employees e ON d.id = e.department_id WHERE d.id = #{id} </select>
- 使用
LEFT JOIN
确保即使Department
没有Employee
,也能正确映射。
- 使用
使用 @Many
注解(Java 接口方式):
Java 类:
1 2 3 4 5 6 7
public class Department { private int id; private String name; @Many(select = "com.example.EmployeeMapper.getEmployeesByDepartmentId") private List<Employee> employees; // Getter 和 Setter 方法 }
@Many
注解:select
属性指定一个全限定的 SQL 映射语句的名称,该语句将返回关联对象的集合(在此为Employee
列表)。
3. 多对多 (Many-to-Many) 关系映射
嵌套结果映射(XML 方式):
resultMap
元素:1 2 3 4 5 6 7 8
<resultMap id="studentResultMap" type="com.example.Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <collection property="courses" ofType="com.example.Course"> <id property="id" column="course_id"/> <result property="name" column="course_name"/> </collection> </resultMap>
- 使用
collection
元素处理多对多关系,将多个Course
对象映射到Student
对象的courses
属性。
- 使用
select
语句:1 2 3 4 5 6 7 8
<select id="getStudentById" resultMap="studentResultMap"> SELECT s.id as student_id, s.name as student_name, c.id as course_id, c.name as course_name FROM students s LEFT JOIN student_course sc ON s.id = sc.student_id LEFT JOIN courses c ON sc.course_id = c.id WHERE s.id = #{id} </select>
- 使用多个
LEFT JOIN
处理多对多关系,通过中间表student_course
关联students
表和courses
表。
- 使用多个
4. 延迟加载
在 XML 中实现延迟加载:
使用
fetchType
属性:1 2 3
<association property="address" javaType="com.example.Address" fetchType="lazy"> <!-- 映射信息 --> </association>
fetchType="lazy"
表示延迟加载,只有在访问关联对象时才会执行相应的 SQL 语句。
在 Java 接口中实现延迟加载:
- 使用
@One
或@Many
注解:1 2
@One(select = "com.example.AddressMapper.getAddressById", fetch = FetchType.LAZY) private Address address;
5. 关联关系的维护
插入和更新操作:
一对一和一对多关系:
- 对于一对一和一对多关系,可以使用
insert
和update
语句更新关联对象。 - 例如,在
Department
中添加Employee
时,可以先插入Employee
,再更新Department
的外键。
1 2 3 4 5 6 7
<insert id="insertEmployee"> INSERT INTO employees (name, department_id) VALUES (#{name}, #{departmentId}) </insert> <update id="updateDepartment"> UPDATE departments SET name = #{name} WHERE id = #{id} </update>
- 对于一对一和一对多关系,可以使用
多对多关系:
使用中间表:
- 插入操作需要同时插入
Student
、Course
和中间表的记录。 - 更新操作可能涉及中间表的修改,例如添加或删除关联关系。
1 2 3
<insert id="insertStudentCourse"> INSERT INTO student_course (student_id, course_id) VALUES (#{studentId}, #{courseId}) </insert>
- 插入操作需要同时插入
总结:
- 结果映射:使用
resultMap
元素及其子元素(id
,result
,association
,collection
)将查询结果映射到 Java 对象,处理不同的关系类型。 - 关联关系处理:使用
@One
和@Many
注解在 Java 类中指定关联关系和加载策略。 - 延迟加载:通过
fetchType
属性或注解的fetch
属性控制关联对象的加载时机,提高性能。 - 关联关系维护:使用
insert
和update
语句处理对象的插入和更新,对于多对多关系,需特别注意中间表的操作。
注意事项:
性能考虑:
- 过度使用立即加载可能导致性能问题,尤其是在复杂对象图中。
- 延迟加载可能导致
LazyInitializationException
,确保在适当的事务或会话范围内访问延迟加载的对象。
SQL 语句设计:
- 确保 SQL 语句正确使用
JOIN
操作符和正确的连接条件,以准确映射关联关系。
- 确保 SQL 语句正确使用
映射维护:
- 对于复杂的关联关系,维护映射配置可能会变得复杂,确保映射的准确性和一致性。
通过以上详细的解释和示例,你可以在 MyBatis 中有效地实现和管理对象之间的各种关系映射,根据业务需求灵活选择不同的映射方式和加载策略,同时注意性能和数据一致性问题。
- 原文作者:Ethan
- 原文链接:https://zhangxingong.fun/post/mybatis-mapping/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。