來源:iyu77.blog.csdn.net/article/details/125761737
MyBatis封裝了JDBC通過Mapper代理的方式,以前繁瑣的操作通過“屬性與字段映射”就簡單化解,MyBatis的動態SQL完美展現了DBMS的獨特魅力
一、多條件查詢
基於Mybatis的多條件查詢,是在Mapper代理的映射文件中寫上原有的SQL,然後接口中寫一個帶參的方法即可,就像這樣:
相比於原生的JDBC那一套,通過MyBatis確實解決了不少硬編碼的問題
但是用戶的查詢永遠是動態的操作,他可能在多個條件中選擇其中少量條件進行查詢,我們的SQL是死的,而用戶需求對應的SQL卻是活的,這樣就會造成不匹配而形成語法錯誤
比如,根據這張表,若是要根據部分字段查出整體,我們可以寫對應需求的SQL,但是我要是查詢的條件變少了或者變多了呢?若用戶只想通過一個條件來查詢,那麼在其他佔位符的位置不輸入於是成了null,過不了語法自然查不了,還得重新寫SQL,多麻煩
這個時候MyBatis的特色就體現出來了——動態SQL
二、動態SQL
SQL語句會隨着用戶的輸入或者外部條件的變化而變化,則稱之爲動態SQL
1. if-where
因爲採用了Mapper代理開發,我們可以通過寫xml的形式來編寫我們的SQL,動態SQL的特性也就在這一舉動中所蘊育,在原有的Mapper文件裏我們進行如下改造,讓平平無奇的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>
標籤可以自動幫我們去掉and”,這樣,不管查詢的條件怎麼變,我跟着這個邏輯流程走就不會出現SQL語法毛病而導致查詢不出來的毛病啦,因爲null的情況已經被if所過濾掉了,真是太哇塞了!
推薦一個開源免費的 Spring Boot 最全教程:
2. choose-when-ortherwise
對於從多個條件中選擇一個的單條件查詢的場景,利用分支嵌套就可以實現動態選擇單條件:
在MyBatis的Mapper代理中,<choose>
相當於switch,<when>
相當於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語句中只會有一個分支生效
當用戶一個條件都不選時,可以在<otherwise>
中寫上1=1
讓語法成立,反之,若選擇了條件則會返回正常結果
3. foreach
對於批量刪除的場景,傳統的方法是通過in關鍵字結合佔位符來確定,就像這樣
where id in (?,?,?)
但對於動態的場景,批量的數量永遠是不確定的,這就導致還需要去改SQL裏的佔位符數量啊,又是一件麻煩事
PS:MyBatis會將數組參數封裝成一個Map集合,默認情況(K-V)array=數組
下面使用了@Param
註解改變了map集合中默認的key
於是MyBatis中的<foreach>
解決了這一麻煩:
本質是通過遍歷的形式,批量刪除的數據是由id數組或者集合來決定,collection
屬性決定了要遍歷哪個數組/集合,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他是一個數組/集合
三、多表操作
多表之間的關係有一對一,一對多,多對一,多對多,每一種都有建表的原則,以用戶-訂單模型爲例
利用傳統的方法進行多表查詢無非是通過id來連接表然後封裝返回結果,MyBatis中也是如此,我們在Mapper文件中寫好表字段之間的映射關係,定義好類型即可,只不過這一過程有點複雜,但一次配好之後即可極大減少硬編碼問題,提高效率
1. 一對一
一個用戶有一張訂單
首先還是那套路,建好實體類,寫好接口方法,配置Mapper文件,而多表操作的麻煩點就在於配置文件,這裏通過例子細說一下
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配置文件
在寫實體類時,要把一個實體寫到另一個實體的屬性裏面,這樣才體現關聯性,就比如“訂單是所用戶擁有的”,正因爲這種關係我們纔會在訂單實體類裏面寫上private User user;
這一屬性,這樣根據id連接的兩個實體才能完美對接!
就像這樣:
通過<association>
把兩張表對應的實體類連接起來,只不過是主鍵ID要用單獨的標籤
property
: 當前實體(order)中的屬性名稱(private User user)javaType
: 當前實體(order)中的屬性的類型(User)
這兩個user有着本質上的卻別,就好像前者是在一個人的名字,後者正是被叫的那個人,MyBatis好像就利用了這一特性,通過標籤的形式連接了兩個實體
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid=u.id
</select>
SQL環節和原來沒什麼區別,同樣也是通過resultMap
把字段和屬性映射封裝。
2.一對多
一個用戶有多張訂單
首先,在原有的User實體中得加上一個表示“用戶有哪些訂單的屬性”private List<Order> orderList;
,目的是爲了把訂單的信息封裝到用戶的這個屬性裏,在Mapper文件中體現:
<collection property="orderList" ofType="order">
<!--封裝order的數據-->
<id column="oid" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="total" property="total"></result>
</collection>
property
:集合名稱,User實體中的orderlist屬性ofType
:當前集合中的數據類型,就是order實體
然後就是寫一對多的SQL:
<select id="findAll" resultMap="userMap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
</select>
總結來看,一對多相比於一對一就是在那個“一”中增添了封裝“多”的屬性而已,然後稍微調整一下SQL
3.多對多
多用戶多角色
多對多的建表原則是引入一張中間表,用於維護外鍵,就是一張表通過中間表找到另一張表
和一對多的模型類似,先在User實體類中增添一個“用戶具備哪些角色”的屬性private List
<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文件中通過映射實現,具體是把兩張外表的id(userId和roleId)在id標籤中配置成同一個屬性,就像這樣:
<id column="userId" property="id"></id>
<id column="roleId" property="id"></id>
SQL環節就得用多對多的套路了
<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>
回想進行多表操作時MyBatis爲我們帶來了什麼?他確實減少了很多硬編碼,我每一次新的SQL只需要在標籤裏改幾個屬性就可以,只要理清字段與屬性的映射關係,在MyBatis中進行多表操作就是一個“對號入座”。
四、註解開發
針對於簡單的CRUD註解開發可以極大地提升效率,顧名思義就是把SQL寫在註解裏
查詢(@Select):
添加(@Insert):
修改(@Update):
刪除(@Delete) :
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這纔是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!