MyBatis where、set、trim
1. 前言
在前面的小節(jié)中,我們一起學(xué)習(xí)了 if 標(biāo)簽,在通過(guò) if 判斷動(dòng)態(tài)插入或查詢的時(shí)候容易產(chǎn)生多余的前綴(如 WHERE)或后綴(如 , ),為了解決這類問(wèn)題 MyBatis 提供了 where、set、trim 三個(gè)實(shí)用的標(biāo)簽。
其中 where 和 set 標(biāo)簽都是 trim 標(biāo)簽的一種特殊情況,不過(guò)使用頻率非常高,因此被單獨(dú)定義成了標(biāo)簽。本小節(jié)我們將一起來(lái)學(xué)習(xí)它們。
2. 定義
慕課解釋:
where
、set
、trim
三個(gè)標(biāo)簽都是為了解決 MyBatis 在動(dòng)態(tài)生成 SQL 時(shí),產(chǎn)生了多余的前綴和后綴的問(wèn)題。
3. 實(shí)例
3.1 where 實(shí)例
<select id="selectUserByIdAndName" resultType="com.imooc.mybatis.model.User">
SELECT * FROM imooc_user
<where>
<if test="id != null">
id = #{id}
</if>
<if test="username != null">
AND username = #{username}
</if>
</where>
</select>
在這個(gè)例子中,id 和 username 均非固定的過(guò)濾參數(shù),只有當(dāng)其不為 null 時(shí)才會(huì)加入到 SQL 語(yǔ)句中。此處 where 標(biāo)簽的作用大概有如下 3 個(gè):
- 在 id 和 username 都為空的情況下,where 標(biāo)簽不會(huì)產(chǎn)生任何 SQL 代碼段,最后的 SQL 語(yǔ)句為:
SELECT * FROM imooc_user
; - 在 id 不為空,username 為空的情況下,或者在 id 不為空,username 也不為空的情況下,where 標(biāo)簽會(huì)自動(dòng)給 SQL 代碼段添加上 WHERE 前綴;
- 在 id 為空,username 不為空的情況下,where 標(biāo)簽會(huì)自定去除 AND 前綴,此時(shí)生成的 SQL 語(yǔ)句為:
SELECT * FROM imooc_user WHERE username = ?
。
3.2 set 實(shí)例
<update id="updateUsernameAndScoreById">
UPDATE imooc_user
<set>
<if test="username != null">
username = #{username},
</if>
id = #{id}
</set>
WHERE id = #{id}
</update>
set 標(biāo)簽會(huì)自動(dòng)在 SQL 語(yǔ)句中添加上相應(yīng)的 SET 前綴,并根據(jù)里面的條件動(dòng)態(tài)地添加相應(yīng)的字段。
由于 SQL update 的語(yǔ)法問(wèn)題,若 set 標(biāo)簽里面條件均不滿足,此時(shí) set 標(biāo)簽也不會(huì)添加上 SET 前綴,但此時(shí) SQL 會(huì)報(bào)語(yǔ)法錯(cuò)誤,所以 set 標(biāo)簽中還是得有一個(gè)必然存在的賦值。
3.3 trim 實(shí)例
<update id="updateUsernameAndScoreById">
UPDATE imooc_user
<trim prefix="SET" suffixOverrides=",">
<if test="username != null">
username = #{username},
</if>
<if test="id != null">
id = #{id}
</if>
</trim>
WHERE id = #{id}
</update>
這里的 trim 實(shí)例實(shí)現(xiàn)了與 set 實(shí)例同樣的功能,set 標(biāo)簽是 trim 標(biāo)簽的一種特殊情況。
trim 標(biāo)簽共有 4 個(gè)屬性,它們的作用分別如下:
- prefix: 前綴屬性,若標(biāo)簽內(nèi)不為空則在 SQL 中添加上前綴;
- prefixOverrides: 前綴覆蓋屬性,若標(biāo)簽中有多余的前綴,將會(huì)被覆蓋(其實(shí)就是丟棄該前綴);
- suffix: 后綴屬性,若標(biāo)簽內(nèi)不為空則在 SQL 中添加上后綴;
- suffixOverrides: 后綴覆蓋屬性,若標(biāo)簽中有多余的后綴,將會(huì)被覆蓋(其實(shí)就是丟棄該后綴)。
這個(gè)例子中,trim 標(biāo)簽的前綴為SET
,后綴覆蓋屬性為,
,所以在標(biāo)簽內(nèi)不為空的情況下給 SQL 語(yǔ)句添加了 SET 關(guān)鍵字,且標(biāo)簽內(nèi)若有多余的,
后綴也會(huì)被丟棄。
4. 實(shí)踐
4.1 例1. 動(dòng)態(tài)插入用戶
請(qǐng)使用 MyBatis 完成對(duì) imooc_user 表動(dòng)態(tài)插入用戶的功能,若用戶屬性值不為 null 則插入該字段,否則不插入字段。
分析:
按照 MyBatis 的開發(fā)模式,先在 UserMapper.xml 文件中添加動(dòng)態(tài)插入用戶的 insert 標(biāo)簽,然后在 UserMapper.java 中添加上對(duì)應(yīng)的方法。
步驟:
首先,在 UserMapper.xml 中添加 insert 標(biāo)簽,并在標(biāo)簽中寫入 SQL,使用 trim 標(biāo)簽來(lái)動(dòng)態(tài)判斷屬性是否為空,若不為空則插入該字段。
<insert id="insertUserDynamic" parameterType="com.imooc.mybatis.model.User">
INSERT INTO imooc_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
username,
</if>
<if test="age != null">
age,
</if>
<if test="score != null">
score,
</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
#{username},
</if>
<if test="age != null">
#{age},
</if>
<if test="score != null">
#{score},
</if>
</trim>
</insert>
這里,我們使用了兩個(gè) trim 標(biāo)簽,一個(gè)用來(lái)動(dòng)態(tài)寫入字段名,另一個(gè)用來(lái)動(dòng)態(tài)寫入字段值;trim 標(biāo)簽的前綴為(
,后綴為)
,當(dāng)出現(xiàn)多余的,
時(shí),會(huì)通過(guò)后綴覆蓋屬性來(lái)丟棄。
然后在 UserMapper.java 中添加上對(duì)應(yīng)的接口方法:
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.imooc.mybatis.model.User;
@Mapper
public interface UserMapper {
int insertUserDynamic(User user);
}
結(jié)果:
通過(guò)如下代碼,我們運(yùn)行 insertUserDynamic 這個(gè)方法。
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUsername("dynamic");
user.setScore(100);
int rows = userMapper.insertUserDynamic(user);
System.out.println(rows);
成功后,結(jié)果為:
1
TIPS: 注意,在 username、score 和 age 均為 null 時(shí), insertUserDynamic 會(huì)報(bào) SQL 語(yǔ)法錯(cuò)誤,但理論上若是所有屬性均為空,那么也不應(yīng)該插入。
5. 小結(jié)
- where、set 以及 trim 將 MyBatis 的動(dòng)態(tài) SQL 發(fā)揮到了極致,為開發(fā)者節(jié)省了大量的精力和時(shí)間。
- trim 標(biāo)簽是 MyBatis 中最為強(qiáng)大的一個(gè)標(biāo)簽,使用它可以方便的完成 SQL 動(dòng)態(tài)插入和動(dòng)態(tài)更新。