電商系統中常見需求:查詢訂單信息,同時級聯獲取下單用戶詳情及訂單包含的多條明細記錄。傳統方案需多次查詢或手動拼裝,MyBatis 的 <resultMap> 配合 <collection> 標籤可一次 SQL 完成映射,且自動去重主表數據。
orders:訂單主表(id, user_id, number, note...)t_user:用戶表(id, name, address, birthday...)orderdetail:訂單明細表(id, order_id, items_id...)SELECT
o.*,
u.address, u.name, u.birthday,
od.id AS orderdetail_id, od.orderid, od.itemsid
FROM orders o
INNER JOIN t_user u ON o.userid = u.id
LEFT JOIN orderdetail od ON od.orderid = o.id;
關鍵點: 使用 LEFT JOIN 保證無明細訂單也能查出;給明細表字段起別名避免與主表字段衝突(如 od.id AS orderdetail_id)。
public class Orders {
private int id;
private String number;
private Date dateTime;
private String note;
private int userId;
// 關聯對象:一對一
private User user;
// 關聯集合:一對多
private List<OrdersDetail> ordersDetails;
// getter/setter 省略
}
public interface OrdersCustomMapper {
/**
* 一對多查詢:訂單 + 用戶 + 明細列表
*/
List<Orders> findOrderAndOrderDetailResultMap();
}
<mapper namespace="com.djp.config.mapper.OrdersCustomMapper">
<!-- 基礎映射:訂單 + 用戶 (一對一) -->
<resultMap id="ordersUserResultMap" type="com.djp.pojo.Orders">
<id column="id" property="id"/>
<result column="note" property="note"/>
<result column="dateTime" property="dateTime"/>
<result column="number" property="number"/>
<result column="userId" property="userId"/>
<!-- 一對一關聯:association -->
<association property="user" javaType="com.djp.pojo.User">
<id column="id" property="id"/> <!-- 用戶表主鍵,去重關鍵 -->
<result column="name" property="name"/>
<result column="address" property="address"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<!-- 擴展映射:繼承基礎映射 + 一對多集合 -->
<resultMap id="orderAndOrderDetailResultMap" type="com.djp.pojo.Orders" extends="ordersUserResultMap">
<!-- 一對多關聯:collection -->
<collection property="ordersDetails" ofType="com.djp.pojo.OrdersDetail">
<id column="orderdetail_id" property="id"/> <!-- 明細主鍵,集合去重關鍵 -->
<result column="orderid" property="orderId"/>
<result column="itemsid" property="itemsId"/>
</collection>
</resultMap>
<select id="findOrderAndOrderDetailResultMap" resultMap="orderAndOrderDetailResultMap">
SELECT o.*, u.address, u.name, u.birthday,
od.id AS orderdetail_id, od.orderid, od.itemsid
FROM orders o
INNER JOIN t_user u ON o.userid = u.id
LEFT JOIN orderdetail od ON od.orderid = o.id
</select>
</mapper>
| 標籤 | 屬性 | 作用 | 去重關鍵 |
|---|---|---|---|
<id> | column | 結果集列名 | MyBatis 根據 <id> 指定的列值判斷對象唯一性,相同值則合併為同一對象,實現主表去重 |
property | 映射到實體屬性 | ||
<association> | property | 映射到實體的關聯對象屬性 | 配合 <id> 實現一對一去重 |
<collection> | property | 映射到實體的集合屬性 | 配合 <id> 實現一對多去重,同一訂單的多條明細聚合到同一 List |
ofType | 集合泛型類型 |
@Test
public void testFindOrderAndOrderDetailResultMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersCustomMapper mapper = sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list = mapper.findOrderAndOrderDetailResultMap();
for (Orders order : list) {
System.out.println("訂單:" + order.getNumber()
+ " | 用戶:" + order.getUser().getName()
+ " | 明細數:" + order.getOrdersDetails().size());
}
}
預期輸出: 訂單不重複,每個訂單包含完整用戶信息與對應明細列表。
<id> 中指定唯一標識列,否則去重失效。id)必須起別名,並在映射中使用別名。extends 復用:基礎映射提取公共部分,擴展映射繼承,減少重複配置。select 屬性)避免超大結果集,但會產生 N+1 問題。掌握 resultMap 的 association 與 collection 組合,是 MyBatis 處理複雜關聯查詢的核心技能,能大幅減少樣板代碼,提升開發效率。