Mybatis一對(duì)多查詢的兩種姿勢(shì)(值得收藏)
前言
最近碰到了Mybatis一對(duì)多查詢的場(chǎng)景,在這里總結(jié)對(duì)比下常見的兩種實(shí)現(xiàn)方式。
本文以常見的訂單表和訂單詳情表來舉例說明;
數(shù)據(jù)庫(kù)表準(zhǔn)備
訂單表 tbl_order
訂單詳情表 tlb_order_detail
ps: 一個(gè)訂單關(guān)聯(lián)多個(gè)訂單詳情,通過order_no訂單號(hào)關(guān)聯(lián);
實(shí)例演示
方法一:聯(lián)合查詢ResultMap映射
sql直接關(guān)聯(lián)查詢,然后結(jié)果集通過resultMap的collection映射
例如 查詢訂單列表,包括訂單詳情
Order.java 中新增字段orderDetailList,用于存詳情列表
public class Order { private Integer id; private String orderNo; private Date orderTime; private Date payTime; private String remark; /**訂單詳情*/ private List<OrderDetail> orderDetailList; //省略get、set
OrderMapper.java 新增查詢方法
List<Order> queryOrderList(Map map);
OrderMapper.xml
<resultMap id="BaseResultMap" type="com.chouxiaozi.mybatisdruid.entity.Order" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="order_no" property="orderNo" jdbcType="VARCHAR" /> <result column="order_time" property="orderTime" jdbcType="TIMESTAMP" /> <result column="pay_time" property="payTime" jdbcType="TIMESTAMP" /> <result column="remark" property="remark" jdbcType="VARCHAR" /> <collection property="orderDetailList" ofType="com.chouxiaozi.mybatisdruid.entity.OrderDetail"> <id column="d_id" property="id" jdbcType="INTEGER" /> <result column="d_order_no" property="orderNo" jdbcType="VARCHAR" /> <result column="good_name" property="goodName" jdbcType="VARCHAR" /> <result column="good_id" property="goodId" jdbcType="INTEGER" /> <result column="good_count" property="goodCount" jdbcType="INTEGER" /> </collection> </resultMap> <select id="queryOrderList" resultMap="BaseResultMap"> SELECT o.*, d.id as d_id,d.order_no as d_order_no,d.good_name,d.good_id,d.good_count FROM tbl_order o LEFT JOIN tbl_order_detail d ON d.order_no = o.order_no where 1=1 <if test="orderNo != null and orderNo != ''"> and o.order_no = #{orderNo} </if> ORDER BY o.order_time desc </select>
查詢結(jié)果展示
[
{
"id": 2,
"orderNo": "DD000002",
"orderTime": "2021-05-09 12:25:57",
"payTime": "2021-05-09 12:25:59",
"remark": "2號(hào)訂單",
"orderDetailList": [
{
"id": 5,
"orderNo": "DD000002",
"goodName": "耳機(jī)",
"goodId": 5,
"goodCount": 1
},
{
"id": 4,
"orderNo": "DD000002",
"goodName": "手機(jī)",
"goodId": 4,
"goodCount": 1
}
]
},
{
"id": 1,
"orderNo": "DD000001",
"orderTime": "2021-05-09 12:25:37",
"payTime": "2021-05-09 12:25:41",
"remark": "1號(hào)訂單",
"orderDetailList": [
{
"id": 2,
"orderNo": "DD000001",
"goodName": "飲料",
"goodId": 2,
"goodCount": 2
},
{
"id": 1,
"orderNo": "DD000001",
"goodName": "瓜子",
"goodId": 1,
"goodCount": 1
},
{
"id": 3,
"orderNo": "DD000001",
"goodName": "礦泉水",
"goodId": 3,
"goodCount": 2
}
]
}
]
原理:sql直接關(guān)聯(lián)查詢,然后結(jié)果集通過resultMap的collection映射,將order_detail表對(duì)應(yīng)的字段映射到orderDetailList字段中。
優(yōu)點(diǎn):條件查詢方便;無論是訂單表還是詳情表如果要進(jìn)行一些條件過濾的話,非常方便,直接寫在where中限制就行。
不足:因?yàn)槭窍汝P(guān)聯(lián)查詢,后映射;如果需要進(jìn)行分頁(yè)查詢的話,這種方式就無法滿足。主表2條數(shù)據(jù),詳情表5條數(shù)據(jù),關(guān)聯(lián)之后就是10條,無法得主表進(jìn)行分頁(yè);解決方法,就是先給主表套個(gè)子查詢limit分頁(yè)后,然后結(jié)果集再跟詳情表進(jìn)行關(guān)聯(lián)查詢;
方法二:子查詢映射
通過resultMap中collection標(biāo)簽的select屬性去執(zhí)行子查詢
還以查詢訂單列表為例
OrderMapper.java
List<Order> queryOrderList2(Map map);
OrderMapper.xml
<!--主查詢的resultMap--> <resultMap id="BaseResultMap2" type="com.chouxiaozi.mybatisdruid.entity.Order" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="order_no" property="orderNo" jdbcType="VARCHAR" /> <result column="order_time" property="orderTime" jdbcType="TIMESTAMP" /> <result column="pay_time" property="payTime" jdbcType="TIMESTAMP" /> <result column="remark" property="remark" jdbcType="VARCHAR" /> <!--select子查詢, column 傳給子查詢的參數(shù)--> <collection property="orderDetailList" ofType="com.chouxiaozi.mybatisdruid.entity.OrderDetail" select="queryDetail" column="order_no"> </collection> </resultMap> <!--主查詢的sql--> <select id="queryOrderList2" resultMap="BaseResultMap2"> SELECT o.* FROM tbl_order o where 1=1 <if test="orderNo != null and orderNo != ''"> and o.order_no = #{orderNo} </if> ORDER BY o.order_time desc </select> <!--子查詢的resultMap--> <resultMap id="detailResuleMap" type="com.chouxiaozi.mybatisdruid.entity.OrderDetail"> <id column="id" property="id" jdbcType="INTEGER" /> <result column="order_no" property="orderNo" jdbcType="VARCHAR" /> <result column="good_name" property="goodName" jdbcType="VARCHAR" /> <result column="good_id" property="goodId" jdbcType="INTEGER" /> <result column="good_count" property="goodCount" jdbcType="INTEGER" /> </resultMap> <!--子查詢的sql--> <select id="queryDetail" resultMap="detailResuleMap"> SELECT * FROM `tbl_order_detail` where order_no = #{order_no} </select>
查詢結(jié)果同上個(gè)例子一樣;
原理:通過collection的select方法去調(diào)用子查詢;所需參數(shù)通過column傳遞;
優(yōu)點(diǎn):無論是分頁(yè)還是普通查詢都能滿足;主表增加過濾條件也很方便,直接在主查詢的sql中增加where條件就行
缺點(diǎn):子查詢不好增加過濾條件;column只能傳遞主表已有的字段。下面提供解決方式;
ps:column傳遞多個(gè)參數(shù) column=“{prop1=col1,prop2=col2}”
例如:實(shí)際場(chǎng)景中,詳情表有個(gè)狀態(tài)字段,只展示狀態(tài)正常的詳情,需要過濾詳情記錄。
本例子沒有狀態(tài)字段,就查詢訂單列表,詳情中不展示瓜子,即詳情記錄中過濾掉good_id = 1的;
在上個(gè)例子基礎(chǔ)上修改如下:
調(diào)用層傳參
Map map = new HashMap(); map.put("goodId", 1); orderMapper.queryOrderList2(map);
orderMapper.xml中增加傳參過濾
展示結(jié)果如下:詳情中已成功過濾掉瓜子;記住,過濾子查詢不會(huì)影響主表記錄;
[
{
"id": 2,
"orderNo": "DD000002",
"orderTime": "2021-05-09 12:25:57",
"payTime": "2021-05-09 12:25:59",
"remark": "2號(hào)訂單",
"orderDetailList": [
{
"id": 4,
"orderNo": "DD000002",
"goodName": "手機(jī)",
"goodId": 4,
"goodCount": 1
},
{
"id": 5,
"orderNo": "DD000002",
"goodName": "耳機(jī)",
"goodId": 5,
"goodCount": 1
}
]
},
{
"id": 1,
"orderNo": "DD000001",
"orderTime": "2021-05-09 12:25:37",
"payTime": "2021-05-09 12:25:41",
"remark": "1號(hào)訂單",
"orderDetailList": [
{
"id": 2,
"orderNo": "DD000001",
"goodName": "飲料",
"goodId": 2,
"goodCount": 2
},
{
"id": 3,
"orderNo": "DD000001",
"goodName": "礦泉水",
"goodId": 3,
"goodCount": 2
}
]
}
]
總結(jié)
方式 | 聯(lián)合查詢映射 | 子查詢映射 |
---|---|---|
原理 | sql查詢完成后再通過resultmap映射結(jié)果 | 主表的數(shù)據(jù)集循環(huán)調(diào)用子查詢 |
分頁(yè) | 不支持分頁(yè)查詢,主表套子查詢也能實(shí)現(xiàn) | 支持分頁(yè) |
條件過濾 | 方便條件過濾 | 傳參也能實(shí)現(xiàn),復(fù)雜參數(shù)例如list不好傳遞給子查詢 ;子查詢過濾不影響主表數(shù)據(jù) |
到此這篇關(guān)于Mybatis一對(duì)多查詢的文章就介紹到這了,更多相關(guān)Mybatis一對(duì)多查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 解決mybatis一對(duì)多查詢r(jià)esultMap只返回了一條記錄問題
- Mybatis使用@one和@Many實(shí)現(xiàn)一對(duì)一及一對(duì)多關(guān)聯(lián)查詢
- springboot整合mybatis-plus基于注解實(shí)現(xiàn)一對(duì)一(一對(duì)多)查詢功能
- springboot整合mybatis實(shí)現(xiàn)簡(jiǎn)單的一對(duì)多級(jí)聯(lián)查詢功能
- mybatis通過中間表實(shí)現(xiàn)一對(duì)多查詢功能
- mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢
- 基于mybatis一對(duì)多查詢內(nèi)層排序的問題
相關(guān)文章
Android設(shè)備如何保證數(shù)據(jù)同步寫入磁盤的實(shí)現(xiàn)
這篇文章主要介紹了Android設(shè)備如何保證數(shù)據(jù)同步寫入磁盤的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Java import導(dǎo)入及訪問控制權(quán)限修飾符原理解析
這篇文章主要介紹了Java import導(dǎo)入及訪問控制權(quán)限修飾符過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Java語(yǔ)法基礎(chǔ)之運(yùn)算符學(xué)習(xí)筆記分享
這篇文章主要為大家分享了Java語(yǔ)法基礎(chǔ)之運(yùn)算符學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)分析
這篇文章主要介紹了java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)分析,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11Java隨機(jī)值設(shè)置(java.util.Random類或Math.random方法)
在編程中有時(shí)我們需要生成一些隨機(jī)的字符串作為授權(quán)碼、驗(yàn)證碼等,以確保數(shù)據(jù)的安全性和唯一性,這篇文章主要給大家介紹了關(guān)于Java隨機(jī)值設(shè)置的相關(guān)資料,主要用的是java.util.Random類或Math.random()方法,需要的朋友可以參考下2024-08-08Java Swing 只關(guān)閉當(dāng)前窗體的實(shí)現(xiàn)
這篇文章主要介紹了Java Swing 只關(guān)閉當(dāng)前窗體的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11SpringBoot自定義FailureAnalyzer詳解
這篇文章主要介紹了SpringBoot自定義FailureAnalyzer詳解,FailureAnalyzer是一種在啟動(dòng)時(shí)攔截?exception?并將其轉(zhuǎn)換為?human-readable?消息的好方法,包含在故障分析中,需要的朋友可以參考下2023-11-11Springboot整合freemarker和相應(yīng)的語(yǔ)法詳解
FreeMarker是一款Spring官方推薦使用的模板引擎。接下來通過本文給大家介紹Springboot整合freemarker和相應(yīng)的語(yǔ)法,感興趣的朋友一起看看吧2021-09-09Java編程實(shí)現(xiàn)暴力破解WIFI密碼的方法分析
這篇文章主要介紹了Java編程實(shí)現(xiàn)暴力破解WIFI密碼的方法,結(jié)合具體實(shí)例形式分析了java暴力破解WiFi密碼的原理、操作步驟、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2018-12-12