User { id, name, age, List<Order> orders }
Order { id, name, user_id }
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<collection property="orders" ofType="Order" column="id" select="selectOrdersByUserId"/>
</resultMap>
<select id="selectOrdersByUserId" parameterType="int" resultType="Order">
SELECT id, name FROM `order` WHERE user_id = #{id}
</select>
<select id="findUserById" resultMap="userMap" parameterType="int">
SELECT * FROM `user` WHERE id = #{id}
</select>
findUserById 查用戶selectOrdersByUserId 查訂單優點:SQL 簡單、可重用、映射清晰。
致命缺點:N+1 問題 —— 查 1 個用戶需 2 次查詢;查 100 個用戶需 101 次查詢。數據庫訪問次數 = 結果集行數 + 1,高併發下極易拖垮資料庫。
<resultMap id="userAutoMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="name" column="order_name"/>
</collection>
</resultMap>
<select id="findAllUsersWithOrders" resultMap="userAutoMap">
SELECT u.id, u.name, u.age, o.id AS order_id, o.name AS order_name
FROM `user` u
LEFT JOIN `order` o ON o.user_id = u.id
</select>
<id> 去重,將同一用戶的多行訂單聚合到 orders 集合優點:只查 1 次庫,無 N+1 問題,大數據量下效能碾壓嵌套查詢。
缺點:SQL 複雜、結果集冗餘(用戶字段重複)、內存組裝開銷大、分頁困難。
<resultMap id="orderMap" type="Order">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="user" column="user_id" javaType="User" select="selectUserById"/> <!-- 嵌套查詢 -->
<!-- 或 -->
<association property="user"> <id property="id" column="user_id"/> ... </association> <!-- 嵌套結果 -->
</resultMap>
association:一對一/多對一(單個對象)collection:一對多/多對多(集合)<id> 標識唯一鍵,確保去重正確(無論嵌套查詢還是結果)。WHERE id IN (...) 批量查關聯表,應用層組裝(手動實現嵌套結果邏輯,但可控分頁、可緩存)。log4j.logger.org.apache.ibatis=DEBUG)觀察實際 SQL 條數,及時發現 N+1。MyBatis 關聯映射只有 association 和 collection 兩把刀,但嵌套查詢 vs 嵌套結果的選擇直接決定系統吞吐量上限。理解 N+1 本質,根據數據量、併發、分頁需求決策,才是架構師級思維。