Mybatis如何使用ognl表達式實現(xiàn)動態(tài)sql
本文講述在mybatis中如何使用ognl表達式實現(xiàn)動態(tài)組裝sql語句
新建Users實體類:
public class Users {
private Integer uid;
private String userName;
private String tel;
//添加上面私有字段的get、set方法
}
新建一個Dao接口類,mybatis配置文件在配置namespace屬性時需要加入這個類的完整類名,找到這個類里的方法執(zhí)行:
public interface UserDao {
/**
* 依據(jù)userName查詢用戶信息
* @param user
* @return
*/
List<Users> listUser(Users user);
/**
* 動態(tài)選擇條件
* @param user
* @return
*/
List<Users> listUser2(Users user);
/**
* 動態(tài)范圍查詢
* @param uids
* @return
*/
List<Users> listUser3(Integer[] uids);
/**
* 動態(tài)更新用戶信息
* @param user
*/
void updateUser(Users user);
/**
* 批量添加
* @param list
*/
void addBatch(List<Users> list);
/**
* 批量刪除
* @param ids
*/
void deleteBatch(int[] ids);
/**
* 批量更新
* @param list
*/
void updateBatch1(List<Users> list);
/**
* 批量更新
* @param list
*/
void updateBatch2(List<Users> list);
}
新建mybatis的配置文件(下面代碼可以作為mybatis配置文件的模板,這里的namespace屬性可以設置為上面的dao類的完整類名):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mapper根節(jié)點的namespace指定Dao接口的完整類名,
因為mybatis在解析的時候要根據(jù)這個類名找到相應dao方法執(zhí)行 --><mapper namespace=""> </mapper>
在mybatis配置文件中寫一條條件查詢sql語句:
<!-- 動態(tài)查詢(使用if拼接條件,適用于多選多的形式) -->
<select id="listUser" parameterType="users" resultMap="userMap">
select u_id, u_name, u_tel from user_info4 user_info
<where>
<if test="userName != null and userName !=''">
u_name = #{userName}
</if>
<if test="tel != null and tel !=''">
and u_tel = #{tel}
</if>
</where>
</select>
這里使用了where和if標簽,<where></where>意思就是sql語句中的where,當然,where直接在sql中寫出來也可以,<if></if>標簽就是條件判斷,test屬性中寫條件語句,如果test中的條件語句為true,那么標簽中的sql語句就會拼接到上面的sql語句中,所以這條sql語句的意思就是如果傳過來的Users對象中,userName字段不為null,或字段值不為空,那么就添加一個對userName的查詢,tel也是如此。
注意:在對tel字段的判斷時,標簽中的sql語句前加了一個and,如果前一條判斷為false,那么mybatis會自動將and關鍵字刪除。
<!-- 動態(tài)查詢(使用choose選擇條件,適用于多選一) -->
<select id="listUser2" parameterType="users" resultMap="userMap">
select u_id, u_name, u_tel from user_info4
<choose>
<when test="userName != null and userName != ''">
where u_name = #{userName}
</when>
<when test="tel != null and tel != ''">
where u_tel = #{tel}
</when>
<otherwise>
order by u_id desc
</otherwise>
</choose>
</select>
這里使用的是choose-when-otherwise標簽,有點類似于java中的switch-case-default選擇條件語句,相比于if標簽,這里只能選擇一個,即多選一。
在這條sql語句中,會按順序判斷when子句,如果所有的when子句都為false,則會執(zhí)行otherwise子句中的sql語句。
<!-- 動態(tài)查詢(使用foreach范圍查詢,適用于in和or語句) -->
<!-- int[] ids = new int[]{1,2,3,4}; -->
<select id="listUser3" parameterType="collection" resultMap="userMap">
select u_id, u_name, u_tel from user_info4
<where>
u_id in
<if test="array != null">
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</where>
</select>
foreach標簽適用于范圍查詢(in和or語句),如遍歷一個id集合,查詢出集合中所有id對應的用戶。在foreach標簽中,collection屬性指定需要遍歷的集合的名稱,這里只有一個參數(shù),所以可以隨意取;item指定遍歷的每一項的別名,open指定在遍歷前需要加上的內(nèi)容,separator指定每遍歷一個后加上的內(nèi)容,close指定遍歷完后需要加上的內(nèi)容,如遍歷上面的ids集合,那么最終得到的內(nèi)容就是 (1,2,3,4) 。
<!-- 動態(tài)更新(使用set動態(tài)更新字段) -->
<update id="updateUser" parameterType="users" >
update user_info4
<trim prefix="set" suffixOverrides=",">
<if test="userName != null and userName != ''">
u_name = #{userName},
</if>
<if test="tel != null and tel != ''">
u_tel = #{tel}
</if>
</trim>
<!-- where u_id = #{uid} -->
<where>
u_id = #{uid}
</where>
</update>
trim標簽用于動態(tài)設值,例如在更新數(shù)據(jù)時,可以動態(tài)將改變的字段設置。在trim標簽中,prefix屬性表示在更新字段之前添加set關鍵字,suffixOverrides表示將最后一個更新字段的逗號替換成suffix指定的空格符,如果不指定suffix默認就是空格。
<!-- 批量添加,利用sql的特性 -->
<insert id="addBatch" parameterType="list">
insert into user_info4(u_id, u_name, u_tel) values
<foreach collection="list" item="user" separator=",">
(#{user.uid}, #{user.userName}, #{user.tel})
</foreach>
</insert>
foreach標簽不僅可以用于范圍查詢,還可以遍歷集合用于批量添加。
因為可以利用sql的特性,例如:insert into user_info4(u_name, u_tel) values('', ''), ('', ''), ('', '');這樣執(zhí)行這條sql語句就可以實現(xiàn)批量添加。
<!-- 批量更新1,這一種方式兼容性較好,當數(shù)據(jù)量大時 -->
<update id="updateBatch1" parameterType="list">
<foreach collection="list" item="user" separator=";">
update user_info4
<set>
u_name = #{user.userName}
</set>
where u_id = #{user.uid}
</foreach>
</update>
foreach還可以用于遍歷出多條sql語句,使得一次可以執(zhí)行多條sql,當然,如果需要MySql執(zhí)行多條批量操作時,需要開啟批量查詢功能,即在MySql的url中加入 allowMultiQueries=true 。
<!-- 批量更新2,使用MySQL的case when語句 -->
<update id="updateBatch2" parameterType="list">
update user_info4 set u_name = case u_id
<foreach collection="list" item="user" separator=" ">
when #{user.uid} then #{user.userName}
</foreach>
end
where u_id in
<foreach collection="list" item="user" open="(" close=")" separator=",">
#{user.uid}
</foreach>
</update>
這里使用的是MySql中的case when語句來更新的,基本語法:
update user_info4 set u_name = case u_id when 3 then '游客1' when 4 then '游客2' end where u_id in(3,4);
Mybatis中的ognl使用總結
經(jīng)常在寫mapper中用到一些OGNL,但是沒怎么總結,使用方法一直模模糊糊的。抽點時間,查了別人的blog,做個簡單的總結
1.概念
OGNL,Object Graph Navigation Language,是一種強大的表達式語言,網(wǎng)上搜索這個概念,多是和structs有關的。但是在mybatis中OGNL應用很廣的;
2.基本參數(shù)
Mybatis中常用的OGNL表達式有以下:
e1 or e2
e1 and e2
e1 == e2,e1 eq e2
e1 != e2,e1 neq e2
e1 lt e2:小于
e1 lte e2:小于等于,其他gt(大于),gte(大于等于)
e1 in e2
e1 not in e2
e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2
!e,not e:非,求反
e.method(args)調用對象方法
e.property對象屬性值
e1[ e2 ]按索引取值,List,數(shù)組和Map
@class@method(args)調用類的靜態(tài)方法
@class@field調用類的靜態(tài)字段值
更加詳細的介紹可以參考官網(wǎng)的介紹:https://commons.apache.org/proper/commons-ognl/language-guide.html
在一定意義上說,mybatis中的動態(tài)sql也是基于OGNL表達式的。其中常用的元素有如下幾種:
if
choose(when,otherwise)
trim
where
set
foreach
3.應用;
OGNL在mybatis中的應用,主要有兩種;
1)動態(tài)SQL表達式;
舉個栗子:
<code class="language-xml hljs has-numbering"><span class="hljs-tag"><<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"demo1"</span> <span class="hljs-attribute">...</span>></span>
</code><pre name="code" class="prettyprint"><code class="language-xml hljs has-numbering"> select id, name from users
<span class="hljs-tag"><<span class="hljs-title">bind</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"nameLike"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"'%' + name + '%'"</span>/></span>
<span class="hljs-tag"><<span class="hljs-title">where</span>></span>
<span class="hljs-tag"><<span class="hljs-title">if</span> <span class="hljs-attribute">test</span>=<span class="hljs-value">"name != null and name != ''"</span>></span>
name like '${nameLike}'
<span class="hljs-tag"></<span class="hljs-title">if</span>></span>
<span class="hljs-tag"></<span class="hljs-title">where</span>></span>
<span class="hljs-tag"></<span class="hljs-title">select</span>></span></code>
其中的bind中的value值會使用OGNL計算,ps,其中bind的參數(shù)調用只能用$獲?。?/p>
2)${param}參數(shù)中
<code class="language-xml hljs has-numbering"><span class="hljs-tag"><<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"demo2"</span> <span class="hljs-attribute">...</span>></span>
select id,name from users
<span class="hljs-tag"><<span class="hljs-title">where</span>></span>
<span class="hljs-tag"><<span class="hljs-title">if</span> <span class="hljs-attribute">test</span>=<span class="hljs-value">"name != null and name != ''"</span>></span>
name like '${'%' + name + '%'}'
<span class="hljs-tag"></<span class="hljs-title">if</span>></span>
<span class="hljs-tag"></<span class="hljs-title">where</span>></span>
<span class="hljs-tag"></<span class="hljs-title">select</span>></span></code>
此處寫的是 ${'%' + name + '%'},而不是 %${name}%,這兩種方式的結果一樣,但是處理過程不一樣。
ps,說明一下#和$的區(qū)別:${} 為原樣輸出,你傳什么,sql里就填入什么,比如有引號它也會原樣填到sql里。#{} 會使用 PreparedStatement,變量處用 ? 代替。
在能使用 #{} 盡量使用它吧,可以防止sql注入。
以下是一個OGNL的調用靜態(tài)方法的示例:
<select id="getRecentQuestionTitle" parameterType="java.lang.String" resultType="java.lang.String">
select title from song_question where questionState = #{value}
<if test="@Ognl@isSolve(value[0],0)">
order by questionTime desc
</if>
<if test="@Ognl@isSolve(value[0],1)">
order by answerTime desc
</if>
limit 0,1
</select>
靜態(tài)方法如下:
public static boolean isSolve(Object o,String soleState){
if(o == null)
return false;
String str = null;
if(o instanceof String[]){
String[]objects = (String[])o;
str = objects[0];
}else if(o instanceof Character){
Character c = (Character) o;
str = Character.toString(c);
}
if(StringUtils.equals(str, soleState))
return true;
return false;
}
如果值為0,則order by questionTime desc 根據(jù)字段questionTime排序。
如果值為1,則order by answerTime desc根據(jù)字段answerTime排序。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
SpringBoot或SpringAI對接DeepSeek大模型的詳細步驟
這篇文章主要介紹了DeepSeek智能助手的使用方法和步驟,包括引入庫、配置環(huán)境變量和配置,文章詳細描述了流式請求和非流式請求的實現(xiàn)方式,需要的朋友可以參考下2025-02-02
Spring為singleton?bean注入prototype?bean
這篇文章主要介紹了Spring為singleton?bean注入prototype?bean,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-07-07
Spring Boot Maven Plugin打包異常解決方案
這篇文章主要介紹了Spring Boot Maven Plugin打包異常解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-11-11
Spring Security之LogoutSuccessHandler注銷成功操作方式
這篇文章主要介紹了Spring Security之LogoutSuccessHandler注銷成功操作方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
如何優(yōu)雅的實現(xiàn)將Collection轉為Map
這篇文章主要介紹了如何優(yōu)雅的實現(xiàn)將Collection轉為Map,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03

