MyBatis 多條件查詢、動態(tài)SQL、多表操作、注解開發(fā),應(yīng)有盡有,一...
點擊關(guān)注公眾號,Java干貨
及時送達(dá)
來源:iyu77.blog.csdn.net/article/details/125761737
MyBatis封裝了JDBC通過Mapper代理的方式,以前繁瑣的操作通過“屬性與字段映射”就簡單化解,MyBatis的動態(tài)SQL完美展現(xiàn)了DBMS的獨特魅力。
一、多條件查詢
基于Mybatis的多條件查詢,是在Mapper代理的映射文件中寫上原有的SQL,然后接口中寫一個帶參的方法即可,就像這樣:

相比于原生的JDBC那一套,通過MyBatis確實解決了不少硬編碼的問題
但是用戶的查詢永遠(yuǎn)是動態(tài)的操作,他可能在多個條件中選擇其中少量條件進(jìn)行查詢,我們的SQL是死的,而用戶需求對應(yīng)的SQL卻是活的,這樣就會造成不匹配而形成語法錯誤
比如,根據(jù)這張表,若是要根據(jù)部分字段查出整體,我們可以寫對應(yīng)需求的SQL,但是我要是查詢的條件變少了或者變多了呢?若用戶只想通過一個條件來查詢,那么在其他占位符的位置不輸入于是成了null,過不了語法自然查不了,還得重新寫SQL,多麻煩

這個時候MyBatis的特色就體現(xiàn)出來了——動態(tài)SQL。
二、動態(tài)SQL
SQL語句會隨著用戶的輸入或者外部條件的變化而變化,則稱之為動態(tài)SQL。另外,最新 MyBatis?系列面試題整理好了,大家可以在Java面試庫小程序在線刷題。
1. if-where
因為采用了Mapper代理開發(fā),我們可以通過寫xml的形式來編寫我們的SQL,動態(tài)SQL的特性也就在這一舉動中所蘊育,在原有的Mapper文件里我們進(jìn)行如下改造,讓平平無奇的SQL煥然一新:
<select?id="selByCondition"?resultMap="rm">
????select?*
????from?mybatis
????<where>
????<if?test="status?!=null">
???????and?STATUS=#{STATUS}
????</if>
????<if?test="companyName?!=null?and?companyName?!=''">
????and?company_name?like?#{companyName}
????</if>
????<if?test="bracdName?!=null?and?bracdName?!=''">
????and?bracd_name?like?#{bracdName}
????</if>
????</where>
</select>
“<where>標(biāo)簽可以自動幫我們?nèi)サ鬭nd”,這樣,不管查詢的條件怎么變,我跟著這個邏輯流程走就不會出現(xiàn)SQL語法毛病而導(dǎo)致查詢不出來的毛病啦,因為null的情況已經(jīng)被if所過濾掉了,真是太哇塞了!
2. choose-when-ortherwise
對于從多個條件中選擇一個的單條件查詢的場景,利用分支嵌套就可以實現(xiàn)動態(tài)選擇單條件:
在MyBatis的Mapper代理中,<choose>相當(dāng)于switch,<when>相當(dāng)于case
<select?id="selByCondition2"?resultMap="rm">
????select?*
????from?mybatis?where
????<choose>
????????<when?test="status?!=null">
????????????STATUS=#{STATUS}
????????</when>
????????<when?test="companyName?!=null?and?companyName?!=''">
????????????company_name?like?#{companyName}
????????</when>
????????<when?test="bracdName?!=null?and?bracdName?!=''">
????????????bracd_name?like?#{bracdName}
????????</when>
????????<otherwise>1=1</otherwise>
????</choose>
</select>
與多條件查詢不同的是,SQL語句中只會有一個分支生效
當(dāng)用戶一個條件都不選時,可以在<otherwise>中寫上1=1讓語法成立,反之,若選擇了條件則會返回正常結(jié)果。
推薦一個開源免費的 Spring Boot 最全教程:https://github.com/javastacks/spring-boot-best-practice
3. foreach
對于批量刪除的場景,傳統(tǒng)的方法是通過in關(guān)鍵字結(jié)合占位符來確定,就像這樣
where?id?in?(?,?,?)
但對于動態(tài)的場景,批量的數(shù)量永遠(yuǎn)是不確定的,這就導(dǎo)致還需要去改SQL里的占位符數(shù)量啊,又是一件麻煩事
“PS:MyBatis會將數(shù)組參數(shù)封裝成一個Map集合,默認(rèn)情況(K-V)array=數(shù)組。
”
下面使用了@Param注解改變了map集合中默認(rèn)的key

于是MyBatis中的<foreach>解決了這一麻煩。
本質(zhì)是通過遍歷的形式,批量刪除的數(shù)據(jù)是由id數(shù)組或者集合來決定,collection屬性決定了要遍歷哪個數(shù)組/集合,item屬性則來存放選出的元素,并把它放在占位符里,separator屬性表示分隔符
<delete?id="deleteById">
????delete?frpm?mybatis?where?id?in
????<foreach?collection="ids"?item="id"?separator=","?open="("?close=")">
????????#{id}
????</foreach>;
</delete>
有人會問為啥這里只有一個#{id},我的屬性字段不止這一個呀?此id非彼id他是一個數(shù)組/集合。

三、多表操作
多表之間的關(guān)系有一對一,一對多,多對一,多對多,每一種都有建表的原則,以用戶-訂單模型為例
利用傳統(tǒng)的方法進(jìn)行多表查詢無非是通過id來連接表然后封裝返回結(jié)果,MyBatis中也是如此,我們在Mapper文件中寫好表字段之間的映射關(guān)系,定義好類型即可,只不過這一過程有點復(fù)雜,但一次配好之后即可極大減少硬編碼問題,提高效率。
1. 一對一
一個用戶有一張訂單

首先還是那套路,建好實體類,寫好接口方法,配置Mapper文件,而多表操作的麻煩點就在于配置文件,這里通過例子細(xì)說一下
1.先把表寫好
CREATE?TABLE?orders?(
id?INT?PRIMARY?KEY?,
ordertime?VARCHAR(20)?NOT?NULL?DEFAULT?'',
total?DOUBLE,
uid?INT);
INSERT?INTO?orders?VALUES(1,2020,2000,1);
INSERT?INTO?orders?VALUES(2,2021,3000,2);
INSERT?INTO?orders?VALUES(3,2022,4000,3);
CREATE?TABLE?USER?(
id?INT?PRIMARY?KEY?,
username?VARCHAR(50)?NOT?NULL?DEFAULT?'',
passwords?VARCHAR(50)?NOT?NULL?DEFAULT?'');
INSERT?INTO?USER?VALUES(1,'lyy',333);
INSERT?INTO?USER?VALUES(2,'myy',444);
INSERT?INTO?USER?VALUES(3,'xyy',555);
2.寫Mapper配置文件
在寫實體類時,要把一個實體寫到另一個實體的屬性里面,這樣才體現(xiàn)關(guān)聯(lián)性,就比如“訂單是所用戶擁有的”,正因為這種關(guān)系我們才會在訂單實體類里面寫上private User user;這一屬性,這樣根據(jù)id連接的兩個實體才能完美對接!
就像這樣:

通過<association>把兩張表對應(yīng)的實體類連接起來,只不過是主鍵ID要用單獨的標(biāo)簽
-
property: 當(dāng)前實體(order)中的屬性名稱(private User user) -
javaType: 當(dāng)前實體(order)中的屬性的類型(User)
這兩個user有著本質(zhì)上的卻別,就好像前者是在一個人的名字,后者正是被叫的那個人,MyBatis好像就利用了這一特性,通過標(biāo)簽的形式連接了兩個實體
<select?id="findAll"?resultMap="orderMap">
???SELECT?*,o.id?oid?FROM?orders?o,USER?u?WHERE?o.uid=u.id
</select>
SQL環(huán)節(jié)和原來沒什么區(qū)別,同樣也是通過resultMap把字段和屬性映射封裝。點擊關(guān)注公眾號,Java干貨及時送達(dá)
2.一對多
一個用戶有多張訂單

首先,在原有的User實體中得加上一個表示“用戶有哪些訂單的屬性”private List<Order> orderList;,目的是為了把訂單的信息封裝到用戶的這個屬性里,在Mapper文件中體現(xiàn):
<collection?property="orderList"?ofType="order">
????<!--封裝order的數(shù)據(jù)-->
????<id?column="oid"?property="id"></id>
????<result?column="ordertime"?property="ordertime"></result>
????<result?column="total"?property="total"></result>
</collection>
-
property:集合名稱,User實體中的orderlist屬性 -
ofType:當(dāng)前集合中的數(shù)據(jù)類型,就是order實體
然后就是寫一對多的SQL:
<select?id="findAll"?resultMap="userMap">
???SELECT?*,o.id?oid?FROM?USER?u,orders?o?WHERE?u.id=o.uid
</select>
總結(jié)來看,一對多相比于一對一就是在那個“一”中增添了封裝“多”的屬性而已,然后稍微調(diào)整一下SQL。另外,最新 MyBatis?系列面試題整理好了,大家可以在Java面試庫小程序在線刷題。
3.多對多
多用戶多角色

多對多的建表原則是引入一張中間表,用于維護(hù)外鍵,就是一張表通過中間表找到另一張表
和一對多的模型類似,先在User實體類中增添一個“用戶具備哪些角色”的屬性private List roleList;其次配置Mapper文件:
<collection?property="roleList"?ofType="role">
???<id?column="roleId"?property="id"></id>
???<result?column="roleName"?property="roleName"></result>
???<result?column="roleDesc"?property="roleDesc"></result>
</collection>
多表的連接是靠中間表,這點在Mapper文件中通過映射實現(xiàn),具體是把兩張外表的id(userId和roleId)在id標(biāo)簽中配置成同一個屬性,就像這樣:
<id?column="userId"?property="id"></id>
<id?column="roleId"?property="id"></id>
<select?id="findUserAndRoleAll"?resultMap="userRoleMap">
????SELECT?*?FROM?USER?u,user-role?ur,role?r?WHERE?u.id=ur.userId?AND?ur.roleId=r.id
</select>
四、注解開發(fā)
針對于簡單的CRUD注解開發(fā)可以極大地提升效率,顧名思義就是把SQL寫在注解里
查詢(@Select):

添加(@Insert):

修改(@Update):

刪除(@Delete) :


Spring Boot 學(xué)習(xí)筆記,這個太全了! 23 種設(shè)計模式實戰(zhàn)(很全) Nacos 2.1.1 正式發(fā)布,真心強(qiáng)! 阿里一面:Spring Bean 如何保證并發(fā)安全? MyBatis 批量插入別再亂用 foreach 了!
Spring Cloud 微服務(wù)最新教程!
