MyBatis多條件查詢(xún)、動(dòng)態(tài)SQL、多表操作、注解開(kāi)發(fā)詳細(xì)教程
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)??
來(lái)源:iyu77.blog.csdn.net/article/details/125761737
一、多條件查詢(xún) 二、動(dòng)態(tài)SQL 1.if-where 2.choose-when-ortherwise 3.foreach 三、多表操作 1.一對(duì)一 2.一對(duì)多 3.多對(duì)多 四、注解開(kāi)發(fā)
MyBatis封裝了JDBC通過(guò)Mapper代理的方式,以前繁瑣的操作通過(guò)“屬性與字段映射”就簡(jiǎn)單化解,MyBatis的動(dòng)態(tài)SQL完美展現(xiàn)了DBMS的獨(dú)特魅力
一、多條件查詢(xún)
基于Mybatis的多條件查詢(xún),是在Mapper代理的映射文件中寫(xiě)上原有的SQL,然后接口中寫(xiě)一個(gè)帶參的方法即可,就像這樣:

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

這個(gè)時(shí)候MyBatis的特色就體現(xiàn)出來(lái)了——?jiǎng)討B(tài)SQL
二、動(dòng)態(tài)SQL
SQL語(yǔ)句會(huì)隨著用戶(hù)的輸入或者外部條件的變化而變化,則稱(chēng)之為動(dòng)態(tài)SQL
1.if-where
因?yàn)椴捎昧薓apper代理開(kāi)發(fā),我們可以通過(guò)寫(xiě)xml的形式來(lái)編寫(xiě)我們的SQL,動(dòng)態(tài)SQL的特性也就在這一舉動(dòng)中所蘊(yùn)育,在原有的Mapper文件里我們進(jìn)行如下改造,讓平平無(wú)奇的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)簽可以自動(dòng)幫我們?nèi)サ鬭nd”,這樣,不管查詢(xún)的條件怎么變,我跟著這個(gè)邏輯流程走就不會(huì)出現(xiàn)SQL語(yǔ)法毛病而導(dǎo)致查詢(xún)不出來(lái)的毛病啦,因?yàn)閚ull的情況已經(jīng)被if所過(guò)濾掉了,真是太哇塞了!
2.choose-when-ortherwise
對(duì)于從多個(gè)條件中選擇一個(gè)的單條件查詢(xún)的場(chǎng)景,利用分支嵌套就可以實(shí)現(xiàn)動(dòng)態(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>
與多條件查詢(xún)不同的是,SQL語(yǔ)句中只會(huì)有一個(gè)分支生效
當(dāng)用戶(hù)一個(gè)條件都不選時(shí),可以在<otherwise>中寫(xiě)上1=1讓語(yǔ)法成立,反之,若選擇了條件則會(huì)返回正常結(jié)果
3.foreach
對(duì)于批量刪除的場(chǎng)景,傳統(tǒng)的方法是通過(guò)in關(guān)鍵字結(jié)合占位符來(lái)確定,就像這樣
where id in (?,?,?)
但對(duì)于動(dòng)態(tài)的場(chǎng)景,批量的數(shù)量永遠(yuǎn)是不確定的,這就導(dǎo)致還需要去改SQL里的占位符數(shù)量啊,又是一件麻煩事
PS:MyBatis會(huì)將數(shù)組參數(shù)封裝成一個(gè)Map集合,默認(rèn)情況(K-V)array=數(shù)組
下面使用了@Param注解改變了map集合中默認(rèn)的key

于是MyBatis中的<foreach>解決了這一麻煩:
本質(zhì)是通過(guò)遍歷的形式,批量刪除的數(shù)據(jù)是由id數(shù)組或者集合來(lái)決定,collection屬性決定了要遍歷哪個(gè)數(shù)組/集合,item屬性則來(lái)存放選出的元素,并把它放在占位符里,separator屬性表示分隔符
<delete id="deleteById">
delete frpm mybatis where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>;
</delete>
有人會(huì)問(wèn)為啥這里只有一個(gè)#{id},我的屬性字段不止這一個(gè)呀?此id非彼id他是一個(gè)數(shù)組/集合
三、多表操作
多表之間的關(guān)系有一對(duì)一,一對(duì)多,多對(duì)一,多對(duì)多,每一種都有建表的原則,以用戶(hù)-訂單模型為例
利用傳統(tǒng)的方法進(jìn)行多表查詢(xún)無(wú)非是通過(guò)id來(lái)連接表然后封裝返回結(jié)果,MyBatis中也是如此,我們?cè)贛apper文件中寫(xiě)好表字段之間的映射關(guān)系,定義好類(lèi)型即可,只不過(guò)這一過(guò)程有點(diǎn)復(fù)雜,但一次配好之后即可極大減少硬編碼問(wèn)題,提高效率
1.一對(duì)一
一個(gè)用戶(hù)有一張訂單
首先還是那套路,建好實(shí)體類(lèi),寫(xiě)好接口方法,配置Mapper文件,而多表操作的麻煩點(diǎn)就在于配置文件,這里通過(guò)例子細(xì)說(shuō)一下
1.先把表寫(xiě)好
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.寫(xiě)Mapper配置文件
在寫(xiě)實(shí)體類(lèi)時(shí),要把一個(gè)實(shí)體寫(xiě)到另一個(gè)實(shí)體的屬性里面,這樣才體現(xiàn)關(guān)聯(lián)性,就比如“訂單是所用戶(hù)擁有的”,正因?yàn)檫@種關(guān)系我們才會(huì)在訂單實(shí)體類(lèi)里面寫(xiě)上private User user;這一屬性,這樣根據(jù)id連接的兩個(gè)實(shí)體才能完美對(duì)接!
就像這樣:
通過(guò)<association>把兩張表對(duì)應(yīng)的實(shí)體類(lèi)連接起來(lái),只不過(guò)是主鍵ID要用單獨(dú)的標(biāo)簽
property: 當(dāng)前實(shí)體(order)中的屬性名稱(chēng)(private User user)SQLType: 當(dāng)前實(shí)體(order)中的屬性的類(lèi)型(User)
這兩個(gè)user有著本質(zhì)上的卻別,就好像前者是在一個(gè)人的名字,后者正是被叫的那個(gè)人,MyBatis好像就利用了這一特性,通過(guò)標(biāo)簽的形式連接了兩個(gè)實(shí)體
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid=u.id
</select>
SQL環(huán)節(jié)和原來(lái)沒(méi)什么區(qū)別,同樣也是通過(guò)resultMap把字段和屬性映射封裝
2.一對(duì)多
一個(gè)用戶(hù)有多張訂單

首先,在原有的User實(shí)體中得加上一個(gè)表示“用戶(hù)有哪些訂單的屬性”private List<Order> orderList;,目的是為了把訂單的信息封裝到用戶(hù)的這個(gè)屬性里,在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:集合名稱(chēng),User實(shí)體中的orderlist屬性ofType:當(dāng)前集合中的數(shù)據(jù)類(lèi)型,就是order實(shí)體
然后就是寫(xiě)一對(duì)多的SQL:
<select id="findAll" resultMap="userMap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
</select>
總結(jié)來(lái)看,一對(duì)多相比于一對(duì)一就是在那個(gè)“一”中增添了封裝“多”的屬性而已,然后稍微調(diào)整一下SQL
3.多對(duì)多
多用戶(hù)多角色

多對(duì)多的建表原則是引入一張中間表,用于維護(hù)外鍵,就是一張表通過(guò)中間表找到另一張表
和一對(duì)多的模型類(lèi)似,先在User實(shí)體類(lèi)中增添一個(gè)“用戶(hù)具備哪些角色”的屬性private List<Role> 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>
多表的連接是靠的中間表,這點(diǎn)在Mapper文件中通過(guò)映射實(shí)現(xiàn),具體是把兩張外表的id(userId和roleId)在id標(biāo)簽中配置成同一個(gè)屬性,就像這樣:
<id column="userId" property="id"></id>
<id column="roleId" property="id"></id>
SQL環(huán)節(jié)就得用多對(duì)多的套路了
<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>
回想進(jìn)行多表操作時(shí)MyBatis為我們帶來(lái)了什么?他確實(shí)減少了很多硬編碼,我每一次新的SQL只需要在標(biāo)簽里改幾個(gè)屬性就可以,只要理清字段與屬性的映射關(guān)系,在MyBatis中進(jìn)行多表操作就是一個(gè)“對(duì)號(hào)入座”
四、注解開(kāi)發(fā)
針對(duì)于簡(jiǎn)單的CRUD注解開(kāi)發(fā)可以極大地提升效率,顧名思義就是把SQL寫(xiě)在注解里
查詢(xún)(@Select):

添加(@Insert):

修改(@Update):

刪除(@Delete) :

1. 面試官:Java 序列化和反序列化為什么要實(shí)現(xiàn) Serializable 接口?
2. 別再用currentTimeMillis統(tǒng)計(jì)耗時(shí)了,太 Low,試試StopWatch吧!
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過(guò)內(nèi)容,記得讀完點(diǎn)一下“在看”,加個(gè)“星標(biāo)”,這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。
點(diǎn)“在看”支持小哈呀,謝謝啦

