一、基礎概念與場景
- 一對多(One-to-Many)
? 定義:一個父對象包含多個子對象。
例如:一個商品(Goods)對應多個商品詳情(GoodsDetail)
? 實體類表現:父類中包含 List<子類>
屬性。
// Goods.java
public class Goods {private List<GoodsDetail> goodsDetails; // 一對多關系
}
- 多對一(Many-to-One)
? 定義:多個子對象屬于一個父對象。
例如:多個商品詳情(GoodsDetail)屬于一個商品(Goods)
? 實體類表現:子類中包含父類對象屬性。
// GoodsDetail.java
public class GoodsDetail {private Goods goods; // 多對一關系
}
二、XML配置實現
- 一對多映射(父→子)
使用<collection>
標簽,核心配置如下:
<!-- GoodsMapper.xml -->
<resultMap id="rmGoods1" type="Goods"><id column="goods_id" property="goodsId"/><!-- 一對多:通過子查詢獲取商品詳情 --><collection property="goodsDetails" select="goodsDetail.selectByGoodsId" column="goods_id"/>
</resultMap><select id="selectOneToMany" resultMap="rmGoods1">SELECT * FROM t_goods LIMIT 0,10
</select>
? 參數解釋:
? select
:指向子查詢的命名空間(如 goodsDetail.selectByGoodsId
)
? column
:傳遞父查詢結果中的字段值(如 goods_id
)到子查詢
- 多對一映射(子→父)
使用<association>
標簽,核心配置如下:
<!-- GoodsDetailMapper.xml -->
<resultMap id="rmGoodsDetail" type="GoodsDetail"><id column="gd_id" property="gdId"/><!-- 多對一:通過父查詢獲取商品信息 --><association property="goods" select="goods.selectById" column="goods_id"/>
</resultMap><select id="selectManyToOne" resultMap="rmGoodsDetail">SELECT * FROM t_goods_detail LIMIT 0,1
</select>
? 參數解釋:
? select
:指向父查詢的命名空間(如 goods.selectById
)
? column
:傳遞當前表的字段值(如 goods_id
)到父查詢
三、聯表查詢優化
- 一對多聯表查詢(避免N+1問題)
直接通過JOIN查詢一次性獲取父子數據:
<resultMap id="rmGoodsJoin" type="Goods"><collection property="goodsDetails" ofType="GoodsDetail"><id column="gd_id" property="gdId"/><result column="gd_pic_url" property="gdPicUrl"/></collection>
</resultMap><select id="selectJoin" resultMap="rmGoodsJoin">SELECT g.*, d.* FROM t_goods g LEFT JOIN t_goods_detail d ON g.goods_id = d.goods_id
</select>
? 優點:減少數據庫查詢次數,提升性能
- 多對一聯表查詢
<resultMap id="rmDetailJoin" type="GoodsDetail"><association property="goods" javaType="Goods"><id column="goods_id" property="goodsId"/><result column="title" property="title"/></association>
</resultMap><select id="selectDetailWithGoods" resultMap="rmDetailJoin">SELECT d.*, g.title FROM t_goods_detail d INNER JOIN t_goods g ON d.goods_id = g.goods_id
</select>
四、常見問題與解決方案
- N+1查詢問題
? 現象:父查詢返回N條數據,觸發N次子查詢,導致性能低下。
? 解決:
? 開啟懶加載:在 mybatis-config.xml
中配置:
```xml
<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>
```
? 使用聯表查詢(如上述第三節)
- 字段名沖突
? 現象:聯表查詢時多個表有相同字段名(如id
)。
? 解決:
? 使用別名區分字段:
```sql
SELECT g.id AS goods_id, d.id AS detail_id
```
? 在 <resultMap>
中明確指定映射關系
五、最佳實踐總結
場景 | 推薦方案 | 適用場景 |
---|---|---|
數據量小 | 分步查詢(<collection> /<association> ) | 字段關聯邏輯簡單 |
數據量大 | 聯表查詢 | 需要一次性獲取完整數據 |
實時性要求高 | 聯表查詢 + 緩存 | 高頻讀取場景 |
更新頻繁 | 分步查詢 + 懶加載 | 減少無效數據加載 |
學習建議:
- 從簡單分步查詢入手,理解映射邏輯
- 逐步嘗試聯表查詢,對比性能差異
- 參考官方文檔中的
<resultMap>
高級用法 - 通過單元測試驗證結果集映射(如
System.out.println(goods.getGoodsDetails().size())
)