MyBatis 中实现多对一和一对多的映射主要依赖于映射文件中的 <association>
和 <collection>
标签。这两种映射关系的实现,是通过嵌套查询或嵌套结果映射来完成的。在源码层面,MyBatis 使用相应的处理器来处理这些标签,最终实现复杂关系对象的装配。
多对一映射(Association)
多对一映射通常用于关联查询中的“多”的一端关联到“一”的一端的情形。在MyBatis中,可以通过 <association>
标签来实现。
映射文件配置
假设有订单(Order)和用户(User)两个实体,其中订单属于某一个用户,即多对一的关系。
首先,定义用户和订单的实体类,然后在订单的映射文件中使用 <association>
来映射用户信息:
<mapper namespace="com.example.OrderMapper"><resultMap id="OrderResultMap" type="Order"><id column="order_id" property="id"/><result column="order_number" property="orderNumber"/><result column="order_date" property="orderDate"/><association property="user" javaType="User"><id column="user_id" property="id"/><result column="username" property="username"/><result column="email" property="email"/></association></resultMap><select id="selectOrderById" resultMap="OrderResultMap">SELECT o.order_id, o.order_number, o.order_date,u.user_id, u.username, u.emailFROM orders oJOIN users u ON o.user_id = u.user_idWHERE o.order_id = #{id}</select>
</mapper>
在上面的示例中,<association>
标签用于映射订单到用户的多对一关系。property
属性指定了目标对象中的属性名,而 javaType
属性指定了关联对象的类型。
源码解析
在解析 <association>
标签时,MyBatis 将创建一个 ResultMapping
对象来存储与关联有关的元数据。解析过程主要由 XMLMapperBuilder
和 ResultMapResolver
完成。
当执行查询时,MyBatis 调用 DefaultResultSetHandler
类来处理结果集。如果存在嵌套查询,则可能先执行主查询,然后根据主查询的结果执行嵌套查询。对于嵌套结果映射,MyBatis 会在处理结果集的过程中根据配置直接填充关联的对象。
一对多映射(Collection)
一对多映射通常用于关联查询中的“一”的一端关联到“多”的一端的情形。在MyBatis中,可以通过 <collection>
标签来实现。
映射文件配置
假设用户(User)和订单(Order)之间的关系,用户可以拥有多个订单,即一对多的关系。
在用户的映射文件中使用 <collection>
来映射订单信息:
<mapper namespace="com.example.UserMapper"><resultMap id="UserResultMap" type="User"><id column="user_id" property="id"/><result column="username" property="username"/><result column="email" property="email"/><collection property="orders" ofType="Order"><id column="order_id" property="id"/><result column="order_number" property="orderNumber"/><result column="order_date" property="orderDate"/></collection></resultMap><select id="selectUserWithOrders" resultMap="UserResultMap">SELECT u.user_id, u.username, u.email,o.order_id, o.order_number, o.order_dateFROM users uLEFT JOIN orders o ON u.user_id = o.user_idWHERE u.user_id = #{id}</select>
</mapper>
在上面的示例中,<collection>
标签用于映射用户到订单的一对多关系。property
属性指定了目标对象中的集合属性名,而 ofType
属性指定了集合中元素的类型。
源码解析
与 <association>
类似,MyBatis 在解析 <collection>
标签时也会创建一个 ResultMapping
对象。解析过程同样主要由 XMLMapperBuilder
和 ResultMapResolver
完成。
在执行查询并处理结果集时,MyBatis 使用 DefaultResultSetHandler
类并采用与 <association>
类似的处理逻辑。不同之处在于,MyBatis 会将每条记录映射到子对象中,并将这些子对象收集到父对象的集合属性中,从而实现一对多的关系映射。
总结
MyBatis 通过 <association>
和 <collection>
标签提供了强大的关系映射能力,允许开发者以相对简单的方式实现复杂的关系映射。在底层,MyBatis 通过解析配置文件中的映射定义,创建相应的映射和结果处理器来实现这些关系映射。这种方式不仅简化了SQL的编写,还为实现复杂的关系数据提取提供了强有力的支持。