Mybatis之動態(tài)sql標(biāo)簽的使用
1.Mybatis動態(tài)sql
MyBatis 的強(qiáng)大特性之一便是它的動態(tài) SQL。如果你有使用 JDBC 或其它類似框架的經(jīng)驗(yàn),你就能體會到根據(jù)不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態(tài) SQL 這一特性可以徹底擺脫這種痛苦。
雖然在以前使用動態(tài) SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射語句中的強(qiáng)大的動態(tài) SQL 語言得以改進(jìn)這種情形。
動態(tài) SQL 元素和 JSTL 或基于類似 XML 的文本處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間了解。MyBatis 3 大大精簡了元素種類,現(xiàn)在只需學(xué)習(xí)原來一半的元素便可。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來淘汰其它大部分元素。
2.常見的動態(tài)sql標(biāo)簽
2.1 if
在現(xiàn)實(shí)的工作場景中,我們通常需要按照不同的維度對數(shù)據(jù)進(jìn)行查詢。比如我們
通過員工管理系統(tǒng)要查詢一個name 為”Tom”的人,在大一點(diǎn)的公司可能有幾個name都為”Tom”的同事并且他們有可能分部在不同的部門,而在小點(diǎn)的公司可能只有一個人根本就不用按部門來過濾,這個時候我們可以通過傳參來控制我們的過濾條件如下:
/**
* @Description employee的dao層代碼
* @Author xiaoqx <Javxuan@163.com>
* @Version V1.0.0
* @Since 2017/11/26
*/
public interface EmployeeMapper {
List<Employee> selectEmployeeList(Employee employee);
}
<select id="selectEmployeeList" resultType="com.worldly.config.entity.Employee" databaseId="mysql">
select
*
from t_emp e
where
<if test="name!=null and name!=''">
e.emp_name=#{name,jdbcType=VARCHAR}
</if>
<if test="dep!=null">
and e.emp_dep=#{dep.id,jdbcType=INTEGER}
</if>
</select>
配合一個“_databaseId”變量的 databaseIdProvider 可用于動態(tài)代碼中,這樣就可以根據(jù)不同的數(shù)據(jù)庫廠商構(gòu)建特定的語句。比如下面的例子:
<insert id="insert">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
<if test="_databaseId == 'oracle'">
select seq_users.nextval from dual
</if>
<if test="_databaseId == 'db2'">
select nextval for seq_users from sysibm.sysdummy1"
</if>
</selectKey>
insert into users values (#{id}, #{name})
</insert>
2.2 where
我們可以想象一下如果我們只要按部門編號查詢某個部門的同事時,生成的sql 語句會是怎么樣的? 很容易得出結(jié)論,最終生成的sql 就會如下:
執(zhí)行后將會報sql語法錯誤。我們可以用另外一個動態(tài)標(biāo)簽來解決這個問題:
<select id="selectEmployeeList" resultType="com.worldly.config.entity.Employee" databaseId="mysql">
select
*
from t_emp e
<where>
<if test="name!=null and name!=''">
and e.emp_name=#{name,jdbcType=VARCHAR}
</if>
<if test="dep!=null">
and e.emp_dep=#{dep.id,jdbcType=INTEGER}
</if>
</where>
</select>
只要將sql放入where動態(tài)標(biāo)簽內(nèi),至少有一個條件符合的時候,才會插入where語句并且會將條件語句前的 and 去掉。

2.3 trim
常用的屬性:
prefix=”where”//給第一符合條件的語句 加上前綴where
prefixOverrides=”and” //將最后一條語句的 前綴and 覆蓋
suffix=”and” //給第一符合條件的語句 加上后綴 and
suffixOverrides=”and”//將最后一條語句的后綴 and 覆蓋
當(dāng)我們把條件語句重新排版一下如下:
<select id="selectEmployeeList" resultType="com.worldly.config.entity.Employee" databaseId="mysql">
select
*
from t_emp e
<where>
<if test="name!=null and name!=''">
e.emp_name=#{name,jdbcType=VARCHAR} and
</if>
<if test="dep!=null">
and e.emp_dep=#{dep.id,jdbcType=INTEGER} and
</if>
</where>
</select>
然后運(yùn)行,結(jié)果如下:發(fā)現(xiàn) 動態(tài)where 標(biāo)簽只會去除 條件語句的第一個and ,這時候動態(tài)where就解決不了這個問題了,就有了一個新的動態(tài)標(biāo)簽trim
動態(tài)xml代碼
<select id="selectEmployeeList" resultType="com.worldly.config.entity.Employee" databaseId="mysql">
select
*
from t_emp e
//表示給第一個符合條件的語句前加 where,把最后一個語句的suffixOverrides="and" 指定的and 覆蓋掉
<trim prefix="where" suffixOverrides="and">
<if test="name!=null and name!=''">
e.emp_name=#{name,jdbcType=VARCHAR} and
</if>
<if test="dep!=null">
e.emp_dep=#{dep.id,jdbcType=INTEGER} and
</if>
</trim>
</select>
2.4 set
類似的用于動態(tài)更新語句的解決方案叫做 set。set 元素可以用于動態(tài)包含需要更新的列,而舍去其它的。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
這里,set 元素會動態(tài)前置 SET 關(guān)鍵字,同時也會刪掉無關(guān)的逗號,因?yàn)橛昧藯l件語句之后很可能就會在生成的 SQL 語句的后面留下這些逗號。(譯者注:因?yàn)橛玫氖恰癷f”元素,若最后一個“if”沒有匹配上而前面的匹配上,SQL 語句的最后就會有一個逗號遺留)
2.5 choose
有時我們不想應(yīng)用到所有的條件語句,而只想從中擇其一項(xiàng)。針對這種情況,MyBatis 提供了 choose 元素,它有點(diǎn)像 Java 中的 switch 語句。
還是上面的例子,但是這次變?yōu)樘峁┝恕皌itle”就按“title”查找,提供了“author”就按“author”查找的情形,若兩者都沒有提供,就返回所有符合條件的 BLOG(實(shí)際情況可能是由管理員按一定策略選出 BLOG 列表,而不是返回大量無意義的隨機(jī)結(jié)果)。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE'
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
2.6 foreach
常用的屬性:
collection 要遍歷的集合;
item 要遍歷的元素;
index 元素在集合中的索引;
open 遍歷以什么開頭 比如 open=”and id in (“;
seprator 遍歷出來的元素以什么分隔;
end 遍歷以什么結(jié)束 end=”)”
動態(tài) SQL 的另外一個常用的操作需求是對一個集合進(jìn)行遍歷,通常是在構(gòu)建 IN 條件語句的時候。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
你可以將任何可迭代對象(如 List、Set 等)、Map 對象或者數(shù)組對象傳遞給 foreach 作為集合參數(shù)。當(dāng)使用可迭代對象或者數(shù)組時,index 是當(dāng)前迭代的次數(shù),item 的值是本次迭代獲取的元素。當(dāng)使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值。
2.7 bind
bind 元素可以從 OGNL 表達(dá)式中創(chuàng)建一個變量并將其綁定到上下文。這個動態(tài)標(biāo)簽可以完美解決#{}在某些時候不適用,而用美元{}又有sql注入的風(fēng)險的情況(${}與#{}的區(qū)別)比如:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
2.8 insert
批量插入mysql 與oracle的區(qū)別:
2.8.1 mysql 批量插入
插入語句
<insert id="insertEmp">
insert into t_emp (id,username)
values
<foreach collection="userList" item="u" separator="," open="(" close=")">
#{u.id},#{u.username}
</foreach>
</insert>
預(yù)編譯結(jié)果
insert into t_emp (id,username) values(?,?),(?,?),(?,?)
你可能會想把整個插入語句進(jìn)行循環(huán)如下:
用;來分隔每一條插入語句
<insert id="insertEmp">
<foreach collection="userList" item="u" separator=";">
insert into t_emp (id,username)
values (#{u.id},#{u.username} )
</foreach>
</insert>
預(yù)編譯結(jié)結(jié)果
insert into t_emp (id,username) values (?,?); insert into t_emp (id,username) values (?,?); insert into t_emp (id,username) values (?,?);
mysql默認(rèn)是不支持這種語法,需要在url 后面的連接屬性增加一個 allowMultiQueries=true; 該屬性默認(rèn)是關(guān)閉的。
2.8.2 oracle批量插入
oracle并不支持mysql這種語法
insert into t_emp (id,username) values(?,?),(?,?),(?,?)
他只能通過如下來完成插入
begin insert into t_emp (id,username) values(?,?); insert into t_emp (id,username) values(?,?); insert into t_emp (id,username) values(?,?); end;
2.9 sql
這個元素可以被用來定義可重用的 SQL 代碼段,可以包含在其他語句中。它可以被靜態(tài)地(在加載參數(shù)) 參數(shù)化. 不同的屬性值通過包含的實(shí)例變化. 比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<select id="selectUsers" resultType="map"> select <include refid="userColumns"><property name="alias" value="t1"/></include>, <include refid="userColumns"><property name="alias" value="t2"/></include> from some_table t1 cross join some_table t2 </select>
到此這篇關(guān)于Mybatis之動態(tài)sql標(biāo)簽的使用的文章就介紹到這了,更多相關(guān)Mybatis 動態(tài)sql標(biāo)簽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 啟動exe程序,傳遞參數(shù)和獲取參數(shù)操作
這篇文章主要介紹了java 啟動exe程序,傳遞參數(shù)和獲取參數(shù)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
解決kafka:org.apache.kafka.common.errors.TimeoutException問題
這篇文章主要介紹了解決kafka:org.apache.kafka.common.errors.TimeoutException問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題詳解
這篇文章主要介紹了SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09
springboot使用JPA時間類型進(jìn)行模糊查詢的方法
這篇文章主要介紹了springboot使用JPA時間類型進(jìn)行模糊查詢的方法,需要的朋友可以參考下2018-03-03

