Mybatis之動(dòng)態(tài)sql標(biāo)簽的使用
1.Mybatis動(dòng)態(tài)sql
MyBatis 的強(qiáng)大特性之一便是它的動(dòng)態(tài) SQL。如果你有使用 JDBC 或其它類似框架的經(jīng)驗(yàn),你就能體會(huì)到根據(jù)不同條件拼接 SQL 語(yǔ)句的痛苦。例如拼接時(shí)要確保不能忘記添加必要的空格,還要注意去掉列表最后一個(gè)列名的逗號(hào)。利用動(dòng)態(tài) SQL 這一特性可以徹底擺脫這種痛苦。 雖然在以前使用動(dòng)態(tài) SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射語(yǔ)句中的強(qiáng)大的動(dòng)態(tài) SQL 語(yǔ)言得以改進(jìn)這種情形。 動(dòng)態(tài) SQL 元素和 JSTL 或基于類似 XML 的文本處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時(shí)間了解。MyBatis 3 大大精簡(jiǎn)了元素種類,現(xiàn)在只需學(xué)習(xí)原來(lái)一半的元素便可。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來(lái)淘汰其它大部分元素。
2.常見(jiàn)的動(dòng)態(tài)sql標(biāo)簽
2.1 if
在現(xiàn)實(shí)的工作場(chǎng)景中,我們通常需要按照不同的維度對(duì)數(shù)據(jù)進(jìn)行查詢。比如我們 通過(guò)員工管理系統(tǒng)要查詢一個(gè)name 為”Tom”的人,在大一點(diǎn)的公司可能有幾個(gè)name都為”Tom”的同事并且他們有可能分部在不同的部門,而在小點(diǎn)的公司可能只有一個(gè)人根本就不用按部門來(lái)過(guò)濾,這個(gè)時(shí)候我們可以通過(guò)傳參來(lái)控制我們的過(guò)濾條件如下:
/** * @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 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>
配合一個(gè)“_databaseId”變量的 databaseIdProvider 可用于動(dòng)態(tài)代碼中,這樣就可以根據(jù)不同的數(shù)據(jù)庫(kù)廠商構(gòu)建特定的語(yǔ)句。比如下面的例子:
<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
我們可以想象一下如果我們只要按部門編號(hào)查詢某個(gè)部門的同事時(shí),生成的sql 語(yǔ)句會(huì)是怎么樣的? 很容易得出結(jié)論,最終生成的sql 就會(huì)如下:
執(zhí)行后將會(huì)報(bào)sql語(yǔ)法錯(cuò)誤。我們可以用另外一個(gè)動(dòng)態(tài)標(biāo)簽來(lái)解決這個(gè)問(wèn)題:
<select 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動(dòng)態(tài)標(biāo)簽內(nèi),至少有一個(gè)條件符合的時(shí)候,才會(huì)插入where語(yǔ)句并且會(huì)將條件語(yǔ)句前的 and 去掉。
2.3 trim
常用的屬性: prefix=”where”//給第一符合條件的語(yǔ)句 加上前綴where prefixOverrides=”and” //將最后一條語(yǔ)句的 前綴and 覆蓋 suffix=”and” //給第一符合條件的語(yǔ)句 加上后綴 and suffixOverrides=”and”//將最后一條語(yǔ)句的后綴 and 覆蓋 當(dāng)我們把條件語(yǔ)句重新排版一下如下:
<select 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) 動(dòng)態(tài)where 標(biāo)簽只會(huì)去除 條件語(yǔ)句的第一個(gè)and ,這時(shí)候動(dòng)態(tài)where就解決不了這個(gè)問(wèn)題了,就有了一個(gè)新的動(dòng)態(tài)標(biāo)簽trim
動(dòng)態(tài)xml代碼
<select resultType='com.worldly.config.entity.Employee' databaseId='mysql'> select * from t_emp e //表示給第一個(gè)符合條件的語(yǔ)句前加 where,把最后一個(gè)語(yǔ)句的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
類似的用于動(dòng)態(tài)更新語(yǔ)句的解決方案叫做 set。set 元素可以用于動(dòng)態(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 元素會(huì)動(dòng)態(tài)前置 SET 關(guān)鍵字,同時(shí)也會(huì)刪掉無(wú)關(guān)的逗號(hào),因?yàn)橛昧藯l件語(yǔ)句之后很可能就會(huì)在生成的 SQL 語(yǔ)句的后面留下這些逗號(hào)。(譯者注:因?yàn)橛玫氖恰癷f”元素,若最后一個(gè)“if”沒(méi)有匹配上而前面的匹配上,SQL 語(yǔ)句的最后就會(huì)有一個(gè)逗號(hào)遺留)
2.5 choose
有時(shí)我們不想應(yīng)用到所有的條件語(yǔ)句,而只想從中擇其一項(xiàng)。針對(duì)這種情況,MyBatis 提供了 choose 元素,它有點(diǎn)像 Java 中的 switch 語(yǔ)句。 還是上面的例子,但是這次變?yōu)樘峁┝恕皌itle”就按“title”查找,提供了“author”就按“author”查找的情形,若兩者都沒(méi)有提供,就返回所有符合條件的 BLOG(實(shí)際情況可能是由管理員按一定策略選出 BLOG 列表,而不是返回大量無(wú)意義的隨機(jī)結(jié)果)。
<select 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 遍歷以什么開(kāi)頭 比如 open=”and id in (“; seprator 遍歷出來(lái)的元素以什么分隔; end 遍歷以什么結(jié)束 end=”)” 動(dòng)態(tài) SQL 的另外一個(gè)常用的操作需求是對(duì)一個(gè)集合進(jìn)行遍歷,通常是在構(gòu)建 IN 條件語(yǔ)句的時(shí)候。比如:
<select resultType='domain.blog.Post'> SELECT * FROM POST P WHERE ID in <foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{item} </foreach></select>
你可以將任何可迭代對(duì)象(如 List、Set 等)、Map 對(duì)象或者數(shù)組對(duì)象傳遞給 foreach 作為集合參數(shù)。當(dāng)使用可迭代對(duì)象或者數(shù)組時(shí),index 是當(dāng)前迭代的次數(shù),item 的值是本次迭代獲取的元素。當(dāng)使用 Map 對(duì)象(或者 Map.Entry 對(duì)象的集合)時(shí),index 是鍵,item 是值。
2.7 bind
bind 元素可以從 OGNL 表達(dá)式中創(chuàng)建一個(gè)變量并將其綁定到上下文。這個(gè)動(dòng)態(tài)標(biāo)簽可以完美解決#{}在某些時(shí)候不適用,而用美元{}又有sql注入的風(fēng)險(xiǎn)的情況(${}與#{}的區(qū)別)比如:
<select 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 批量插入
插入語(yǔ)句
<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(?,?),(?,?),(?,?)
你可能會(huì)想把整個(gè)插入語(yǔ)句進(jìn)行循環(huán)如下: 用;來(lái)分隔每一條插入語(yǔ)句
<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)是不支持這種語(yǔ)法,需要在url 后面的連接屬性增加一個(gè) allowMultiQueries=true; 該屬性默認(rèn)是關(guān)閉的。
2.8.2 oracle批量插入
oracle并不支持mysql這種語(yǔ)法
insert into t_emp (id,username) values(?,?),(?,?),(?,?)
他只能通過(guò)如下來(lái)完成插入
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
這個(gè)元素可以被用來(lái)定義可重用的 SQL 代碼段,可以包含在其他語(yǔ)句中。它可以被靜態(tài)地(在加載參數(shù)) 參數(shù)化. 不同的屬性值通過(guò)包含的實(shí)例變化. 比如:
<sql id='userColumns'> ${alias}.id,${alias}.username,${alias}.password </sql>
<select 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之動(dòng)態(tài)sql標(biāo)簽的使用的文章就介紹到這了,更多相關(guān)Mybatis 動(dòng)態(tài)sql標(biāo)簽內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. 恢復(fù)從 Access 2000、 Access 2002 或 Access 2003 中數(shù)據(jù)庫(kù)刪除表的方法2. Mysql入門系列:MYSQL創(chuàng)建、刪除、索引和更改表3. 啟動(dòng)MYSQL出錯(cuò) Manager of pid-file quit without updating file.4. Mysql入門系列:建立MYSQL客戶機(jī)程序的一般過(guò)程5. Microsoft Office Access修改代碼字體大小的方法6. ACCESS轉(zhuǎn)SQL數(shù)據(jù)庫(kù)相關(guān)的幾個(gè)技能7. mysql數(shù)據(jù)存放的位置在哪8. MySQL 8.0 之索引跳躍掃描(Index Skip Scan)9. 數(shù)據(jù)庫(kù)人員手冊(cè)之ORACLE應(yīng)用源碼10. 循序漸進(jìn)講解Oracle數(shù)據(jù)庫(kù)管理員的職責(zé)
