一、MyBatis 映射兩大方式對比
| 特性 | resultType | resultMap |
| 適用場景 | 扁平化查詢、單表、簡單連接 | 複雜關聯、巢狀結果、延遲加載 |
| 映射方式 | 列名自動匹配屬性名 | 手動定義列→屬性、關聯映射 |
| 關聯物件 | 需建立扁平化 DTO | 直接映射到巢狀物件/集合 |
| 延遲加載 | ❌ 不支援 | ✅ 支援 |
| 繼承複用 | ❌ | ✅ extends 屬性 |
二、一對一關聯映射:association
場景:查詢訂單 + 關聯用戶
方式 1:resultType + 扁平化 DTO
public class OrderUserDTO extends Order {
private String username;
private String sex;
private String address;
// getter/setter
}
<select id="findOrderUser" resultType="com.example.dto.OrderUserDTO">
SELECT o.*, u.username, u.sex, u.address
FROM orders o JOIN user u ON o.user_id = u.id
</select>
方式 2:resultMap + association(推薦)
public class Order {
private Integer id;
private Integer userId;
private User user; // 關聯物件
// getter/setter
}
<resultMap id="orderUserMap" type="com.example.po.Order">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<association property="user" javaType="com.example.po.User">
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="address" property="address" />
</association>
</resultMap>
<select id="findOrderUserMap" resultMap="orderUserMap">
SELECT o.*, u.username, u.sex, u.address
FROM orders o JOIN user u ON o.user_id = u.id
</select>
三、一對多集合映射:collection
場景:查詢訂單 + 訂單明細(多筆)
public class Order {
// ... 原有欄位
private List<OrderDetail> orderDetails; // 集合屬性
}
<resultMap id="orderDetailMap" type="com.example.po.Order" extends="orderUserMap">
<collection property="orderDetails" ofType="com.example.po.OrderDetail">
<id column="detail_id" property="id" />
<result column="items_id" property="itemsId" />
<result column="items_num" property="itemsNum" />
<result column="orders_id" property="ordersId" />
</collection>
</resultMap>
<select id="findOrderDetails" resultMap="orderDetailMap">
SELECT o.*, u.username, u.sex, u.address,
d.id detail_id, d.items_id, d.items_num, d.orders_id
FROM orders o
JOIN user u ON o.user_id = u.id
JOIN order_detail d ON d.orders_id = o.id
</select>
關鍵屬性對比
| 屬性 | association | collection |
| 映射目標 | 單一物件 | 集合 |
| 類型指定 | javaType | ofType |
| 唯一標識 | 子 <id> 必填 | 子 <id> 必填(去重依據) |
四、多對多:巢狀 association + collection 組合
場景:用戶 → 訂單(多) → 明細(多) → 商品(一)
<resultMap id="userOrderItemMap" type="com.example.po.User">
<id column="user_id" property="id" />
<result column="username" property="username" />
<collection property="orders" ofType="com.example.po.Order">
<id column="order_id" property="id" />
<result column="number" property="number" />
<collection property="orderDetails" ofType="com.example.po.OrderDetail">
<id column="detail_id" property="id" />
<result column="items_num" property="itemsNum" />
<association property="item" javaType="com.example.po.Item">
<id column="item_id" property="id" />
<result column="item_name" property="name" />
<result column="item_price" property="price" />
</association>
</collection>
</collection>
</resultMap>
五、延遲加載:按需查詢優化效能
全域開啟
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" /> <-- 只加載調用的屬性 -->
映射配置
<association property="user" javaType="User" select="selectUserById" column="user_id" />
<collection property="details" ofType="Detail" select="selectDetailsByOrderId" column="id" />
對應查詢方法
<select id="selectUserById" resultType="User">
SELECT * FROM user WHERE id = #{user_id}
</select>
<select id="selectDetailsByOrderId" resultType="Detail">
SELECT * FROM order_detail WHERE orders_id = #{id}
</select>
六、resultMap 繼承優化
<resultMap id="baseOrderMap" type="Order">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<!-- 通用欄位 -->
</resultMap>
<resultMap id="orderWithUserMap" extends="baseOrderMap">
<association property="user" javaType="User">...</association>
</resultMap>
<resultMap id="orderWithDetailsMap" extends="baseOrderMap">
<collection property="details" ofType="Detail">...</collection>
</resultMap>
七、選型建議總結
- 簡單扁平查詢、報表導出 → resultType(開發快)
- 領域模型豐富、關聯複雜、需延遲加載 → resultMap(維護性好)
- 高併發讀多寫少 → 開啟二級快取 + 延遲加載
- 避免 N+1 問題:批量查詢用
collection 一次性載入,或手寫 SQL 聯表