一、引言
在 MyBatis 的世界里,当处理数据库中的关联关系时,Association
和Collection
是两个非常重要的概念。它们能够帮助我们高效地获取和处理与主实体相关的其他实体信息。无论是一对一(Association
)还是一对多(Collection
)的关系,正确地使用它们可以让我们的持久层代码更加清晰和高效。
二、Association
的使用方法
(一)含义
Association
主要用于处理一对一的关联关系。例如,在一个简单的用户系统中,一个用户可能对应一个用户详情(如用户的扩展信息),这种关系就可以通过Association
来映射。
(二)XML 配置方式
- 基本查询与结果映射
- 假设我们有
User
表和UserDetail
表,UserDetail
表通过user_id
外键关联到User
表的id
。 - 首先,在
UserMapper.xml
中定义查询语句:
- 假设我们有
收起
xml
复制
<select id="getUserWithDetailById" resultMap="UserWithDetailResultMap">
select u.*, ud.*
from user u
left join user_detail ud on u.id = ud.user_id
where u.id = #{id}
</select>
- 然后,定义
resultMap
来映射结果:
收起
xml
复制
<resultMap id="UserWithDetailResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<association property="userDetail" javaType="UserDetail">
<id property="id" column="user_detail_id"/>
<result property="address" column="address"/>
</association>
</resultMap>
- 在这里,
select
语句通过left join
将两张表的数据一起查询出来。在resultMap
中,id
和result
标签用于映射User
表的列到User
实体的属性。Association
标签用于处理一对一关系,property
属性指定了在User
实体中关联UserDetail
对象的属性名,javaType
属性指定了关联对象的类型为UserDetail
。在Association
内部的id
和result
标签用于映射UserDetail
表的列到UserDetail
实体的属性。
- 延迟加载(嵌套查询)方式
- MyBatis 也支持通过嵌套查询来实现关联查询并进行延迟加载。例如:
收起
xml
复制
<resultMap id="UserWithDetailLazyResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<association property="userDetail" javaType="UserDetail"
select="com.example.dao.UserDetailMapper.getUserDetailById"
column="id">
</association>
</resultMap>
- 在这个
resultMap
中,Association
标签的select
属性指定了一个查询UserDetail
对象的方法(在UserDetailMapper.xml
中定义),column
属性指定了传递给这个查询方法的参数(通常是关联外键的值)。这样,只有当访问User
对象中的userDetail
属性时,才会执行UserDetailMapper
中的查询方法,实现了延迟加载,提高了性能。
(三)注解方式
- 示例代码
- 假设我们使用 MyBatis 的注解方式来处理一对一关系。
收起
java
复制
public interface UserMapper {
@Select("select * from user where id = #{id}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "userDetail", javaType = UserDetail.class,
one = @One(select = "com.example.dao.UserDetailMapper.getUserDetailById"),
column = "id")
})
User getUserWithDetailById(int id);
}
- 在这个示例中,
@Results
注解用于定义结果集映射。@Result
注解中的property
指定实体类中的属性名,column
指定数据库表中的列名。对于关联关系部分,one = @One(select = "com.example.dao.UserDetailMapper.getUserDetailById")
表示这是一个一对一的关联查询,select
属性指定了查询关联对象的方法,column
属性指定了传递给该方法的参数,和 XML 配置中的延迟加载方式类似,实现了关联对象的查询。
三、Collection
的使用方法
(一)含义
Collection
用于处理一对多的关联关系。例如,一个用户可能有多个订单,这种用户和订单之间的一对多关系就可以通过Collection
来映射。
(二)XML 配置方式
- 基本查询与结果映射
- 假设我们有
User
表和Order
表,Order
表通过user_id
外键关联到User
表的id
。 - 首先,在
UserMapper.xml
中定义查询语句:
- 假设我们有
收起
xml
复制
<select id="getUserWithOrdersById" resultMap="UserWithOrdersResultMap">
select u.*, o.*
from user u
left join orders o on u.id = o.user_id
where u.id = #{id}
</select>
- 然后,定义
resultMap
:
收起
xml
复制
<resultMap id="UserWithOrdersResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="orderNumber" column="order_number"/>
</collection>
</resultMap>
- 在这里,
select
语句通过left join
将用户和订单的数据一起查询出来。在resultMap
中,id
和result
标签用于映射User
表的列到User
实体的属性。Collection
标签用于处理一对多关系,property
属性指定了在User
实体中关联订单集合的属性名(假设User
类中有一个List<Order>
类型的属性叫orders
),ofType
属性指定了集合中元素的类型为Order
。在Collection
内部的id
和result
标签用于映射Order
表的列到Order
实体的属性。
- 延迟加载(嵌套查询)方式
- 同样可以使用嵌套查询实现延迟加载。例如:
收起
xml
复制
<resultMap id="UserWithOrdersLazyResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="orders" ofType="Order"
select="com.example.dao.OrderMapper.getOrdersByUserId"
column="id">
</collection>
</resultMap>
- 在这个
resultMap
中,Collection
标签的select
属性指定了一个查询订单集合的方法(在OrderMapper.xml
中定义),column
属性指定了传递给这个查询方法的参数(通常是关联外键的值)。只有当访问User
对象中的orders
属性时,才会执行OrderMapper
中的查询方法,实现了延迟加载。
(三)注解方式
- 示例代码
- 假设我们使用注解方式来处理一对多关系。
收起
java
复制
public interface UserMapper {
@Select("select * from user where id = #{id}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "username" column = "username"),
@Result(property = "orders", javaType = ArrayList.class, ofType = Order.class,
many = @Many(select = "com.example.dao.OrderMapper.getOrdersByUserId"),
column = "id")
})
User getUserWithOrdersById(int id);
}
- 在这个示例中,
@Results
注解用于定义结果集映射。@Result
注解中的property
指定实体类中的属性名,column
指定数据库表中的列名。对于关联关系部分,many = @Many(select = "com.example.dao.OrderMapper.getOrdersByUserId")
表示这是一个一对多的关联查询,select
属性指定了查询关联对象集合的方法,column
属性指定了传递给该方法的参数,实现了一对多关联对象的查询和延迟加载(如果配置了的话)。
四、Association
和Collection
的区别
(一)关联关系类型
Association
处理一对一的关联关系,例如一个用户对应一个用户详情。它主要关注的是单个相关对象与主对象的映射。Collection
处理一对多的关联关系,比如一个用户对应多个订单。它强调的是主对象与一组相关对象(通常是一个集合)的映射。
(二)配置细节
- 在 XML 配置的
resultMap
中:Association
使用javaType
属性来指定关联对象的类型,因为它是一对一的关系,只涉及一个对象类型。Collection
使用ofType
属性来指定集合中元素的类型,因为它是一对多的关系,需要明确集合内元素的类型。
- 在注解方式中:
Association
使用one = @One
来表示一对一关联查询。Collection
使用many = @Many
来表示一对多关联查询。
(三)数据结构
Association
在实体类中对应的属性通常是一个单一对象,例如User
类中的UserDetail userDetail
。Collection
在实体类中对应的属性是一个集合,例如User
类中的List<Order> orders
。
希望这篇文章能够帮助你更好地理解和使用 MyBatis 中的Association
和Collection
,在实际的开发中能够根据具体的关联关系类型灵活地选择和应用它们。