MyBatis 的自動映射機制(resultType)雖然方便,但要求數據庫列名與 Java 實體屬性名嚴格一致。現實開發中,下劃線命名 vs 駝峰命名、多表關聯查詢、嵌套結果集 等場景屢見不鮮,這時 <resultMap> 就是破局利器。本文從基礎配置到進階關聯映射,系統梳理 ResultMap 核心用法。
user_name vs userName)<mapper namespace="com.example.dao.UserMapper">
<!-- id: 唯一標譽;type: 目標實體全限定名或別名 -->
<resultMap id="userResultMap" type="com.example.entity.User">
<!-- id 標籤標識主鍵,對緩存與比較至關重要 -->
<id property="id" column="user_id" />
<result property="userName" column="user_name" />
<result property="email" column="email" />
<result property="createTime" column="create_time" />
</resultMap>
<select id="selectById" resultMap="userResultMap">
SELECT user_id, user_name, email, create_time
FROM sys_user
WHERE user_id = #{id}
</select>
</mapper>
| 標籤 | 用途 | 關鍵屬性 |
|---|---|---|
<id> | 主鍵列映射(影響 equals/hashCode 與緩存鍵) | property, column, javaType, typeHandler |
<result> | 普通列映射 | 同 id |
<constructor> | 構造方法注入(不可變對象) | <idArg>, <arg> |
<association> | 一對一關聯對象 | javaType, resultMap, select (嵌套查詢) |
<collection> | 一對多集合映射 | ofType, resultMap, select |
<resultMap id="userDetailMap" type="User">
<id property="id" column="u_id" />
<result property="username" column="u_name" />
<association property="profile" javaType="UserProfile">
<id property="id" column="p_id" />
<result property="avatar" column="p_avatar" />
<result property="bio" column="p_bio" />
</association>
</resultMap>
<select id="selectUserWithProfile" resultMap="userDetailMap">
SELECT u.id u_id, u.username u_name,
p.id p_id, p.avatar p_avatar, p.bio p_bio
FROM sys_user u
LEFT JOIN user_profile p ON u.id = p.user_id
WHERE u.id = #{id}
</select>
<resultMap id="orderMap" type="Order">
<id property="id" column="o_id" />
<result property="orderNo" column="o_no" />
<result property="totalAmount" column="o_total" />
<collection property="items" ofType="OrderItem">
<id property="id" column="i_id" />
<result property="skuCode" column="i_sku" />
<result property="quantity" column="i_qty" />
<result property="price" column="i_price" />
</collection>
</resultMap>
<select id="selectOrderWithItems" resultMap="orderMap">
SELECT o.id o_id, o.order_no o_no, o.total_amount o_total,
i.id i_id, i.sku_code i_sku, i.quantity i_qty, i.price i_price
FROM t_order o
LEFT JOIN t_order_item i ON o.id = i.order_id
WHERE o.id = #{id}
</select>
當關聯數據量大或邏輯複雜,可拆分為多條 SQL,通過 select 屬性引用:
<resultMap id="orderLazyMap" type="Order">
<id property="id" column="id" />
<collection property="items"
select="com.example.dao.OrderItemMapper.selectByOrderId"
column="id" /> <!-- column 將作為參數傳給嵌套查詢 -->
</resultMap>
注意:嵌套查詢默認開啟延遲加載(需全局 lazyLoadingEnabled=true),N+1 問題需權衡。
<id>:否則緩存、去重、實體比較失效。SELECT u.id AS u_id, p.id AS p_id 避免列名衝突。mapUnderscoreToCamelCase=true 可省去大量 <result>,但關聯映射仍需手寫。extends 屬性繼承基礎映射,減少重複。| 維度 | resultType | resultMap |
|---|---|---|
| 適用場景 | 列名=屬性名、單表、無關聯 | 列名不一致、多表關聯、複雜類型轉換 |
| 開發效率 | 極高(零配置) | 需編寫 XML,但可復用 |
| 運行性能 | 略高(無解析開銷) | 可忽略差異 |
| 可維護性 | 差(隱式依賴命名約定) | 優(顯式聲明映射關係) |
ResultMap 是 MyBatis 將關係數據映射為豐富領域模型的核心橋樑。熟練掌握 <association>、<collection> 及嵌套查詢,能讓你在複雜業務場景下遊刃有餘,告別「手寫映射循環」的痛苦。