Mybatis中的動態SQL在xml中支援的幾種常用標籤
mybatis3之後,採用了功能強大的OGNL表示式語言消除了許多其它繁瑣的標籤,現在動態SQL在xml中支援的幾種標籤:
- if
- choose(when、otherwise)
- trim(where、set)
- foreach
- bind
一.if標籤
if標籤通常用於where語句中,通過判斷引數值來決定是否使用某個查詢條件,它也經常用於UPDATE語句中判斷是否更新某一個欄位,還可以再INSERT語句中用來判斷是否插入某個欄位的值。
1.1 在where條件中使用if
用法:含義就是當if滿足時,就執行標籤體中的內容。
需求:準備如下資料表,當只輸入使用者名稱的時候,就根據這個使用者名稱進行模糊查詢匹配的使用者;當只輸入郵箱時,就根據郵箱完全匹配使用者胡;當兩者都同時輸入時,就需要用這兩個條件去查詢匹配的使用者。
表格:
貼下關鍵程式碼:
(1)controller
@PostMapping("/selectByUser") public List<SysUser> selectByUser(){ SysUser sysUser=new SysUser(); sysUser.setUserName("tes"); return userService.selectByUser(sysUser); }
說明:這裡只傳入了userName。而userEmail為null
(2)service實現類
1 @OverrideView Code2 public List<SysUser> selectByUser(SysUser sysUser) { 3 return userMapper.selectByUser(sysUser); 4 }
(3)mapper介面
List<SysUser> selectByUser(SysUser sysUser);
(4)mapper.xm<select id="selectByUser" resultType="com.example.demo.dao.SysUser"> select id,
user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, created_time createTime from sys_user where 1=1 <if test="userName!=null and userName!=''"> and user_name like concat('%',#{userName},'%') </if> <if test="userEmail!=null and userEmail!=''"> and user_email=#{userEmail} </if> </select>
說明:1.if標籤內有一個必填的屬性test,test的值是一個符合OGNL要求的判斷表示式,表示式的結果可以認為是ture或者false.
2.當有多個判斷條件時,可以使用and或者or進行搭配。
3.上面兩個if,它們是平級的關係,只要有滿足if條件的,if標籤內的 and user_x=... 這一句就會接在where語句後面。如果不滿足,就不會有。
4.這裡寫了一個where 1=1 是為了保證當2個if語句都沒有的時候,不會直接以where結束,這樣sql語句就會報錯。
這種寫法where1=1不美觀,後面可以採用where標籤來拯救它。
(5)實體類
1 package com.example.demo.dao; 2 3 4 import java.sql.Date; 5 6 public class SysUser { 7 /** 8 * 使用者ID 9 */ 10 private Long id; 11 /** 12 * 使用者名稱 13 */ 14 private String userName; 15 /** 16 * 密碼 17 */ 18 private String userPassword; 19 /** 20 * 郵箱 21 */ 22 private String userEmail; 23 /** 24 * 簡介 25 */ 26 private String userInfo; 27 /** 28 * 頭像 29 */ 30 private byte[] headImg; 31 /** 32 * 建立時間 33 */ 34 private Date createTime; 35 36 public Long getId() { 37 return id; 38 } 39 40 public void setId(Long id) { 41 this.id = id; 42 } 43 44 public String getUserName() { 45 return userName; 46 } 47 48 public void setUserName(String userName) { 49 this.userName = userName; 50 } 51 52 public String getUserPassword() { 53 return userPassword; 54 } 55 56 public void setUserPassword(String userPassword) { 57 this.userPassword = userPassword; 58 } 59 60 public String getUserEmail() { 61 return userEmail; 62 } 63 64 public void setUserEmail(String userEmail) { 65 this.userEmail = userEmail; 66 } 67 68 public String getUserInfo() { 69 return userInfo; 70 } 71 72 public void setUserInfo(String userInfo) { 73 this.userInfo = userInfo; 74 } 75 76 public byte[] getHeadImg() { 77 return headImg; 78 } 79 80 public void setHeadImg(byte[] headImg) { 81 this.headImg = headImg; 82 } 83 84 public Date getCreateTime() { 85 return createTime; 86 } 87 88 public void setCreateTime(Date createTime) { 89 this.createTime = createTime; 90 } 91 }View Code
採用postman模擬請求,會得到三條和名字模糊匹配的記錄:
1 [ 2 { 3 "id": 3, 4 "userName": "test1", 5 "userPassword": "123456", 6 "userEmail": "[email protected]", 7 "userInfo": "test1", 8 "headImg": null, 9 "createTime": "2020-03-04" 10 }, 11 { 12 "id": 1001, 13 "userName": "test", 14 "userPassword": "123456", 15 "userEmail": "[email protected]", 16 "userInfo": "管理員", 17 "headImg": null, 18 "createTime": "2020-03-19" 19 }, 20 { 21 "id": 1002, 22 "userName": "test1", 23 "userPassword": "123456", 24 "userEmail": "[email protected]", 25 "userInfo": "test1", 26 "headImg": null, 27 "createTime": "2020-03-25" 28 }, 29 { 30 "id": 1003, 31 "userName": "test1", 32 "userPassword": "123456", 33 "userEmail": "[email protected]", 34 "userInfo": "test1", 35 "headImg": null, 36 "createTime": "2020-03-29" 37 }, 38 { 39 "id": 1004, 40 "userName": "test1", 41 "userPassword": "123456", 42 "userEmail": "[email protected]", 43 "userInfo": "test1", 44 "headImg": null, 45 "createTime": "2020-03-29" 46 } 47 ]View Code
1.2 在UPDATE更新列中使用if標籤
需求:只更新發生變化的欄位。
(1)controller
1 @PostMapping("/updateBySelective") 2 int updateBySelective(SysUser sysUser){ 3 sysUser.setUserName("hello"); 4 sysUser.setId(1L); 5 return userService.updateBySelective(sysUser); 6 }View Code
(2)service實現類
1 @Override 2 public int updateBySelective(SysUser sysUser) { 3 return userMapper.updateBySelective(sysUser); 4 }View Code
(3)mapper介面
1 int updateBySelective(SysUser sysUser);
View Code
(4)mapper.xml
<update id="updateBySelective"> update sys_user set <if test="userName!=null and userName!=''"> user_name=#{userName}, </if> <if test="userPassword!=null and userPassword!=''"> user_password=#{userPassword}, </if> <if test="userEmail!=null and userEmail!=''"> user_email=#{userEmail}, </if> <if test="userInfo!=null and userInfo!=''"> user_info=#{userInfo}, </if> <if test="headImg!=null"> head_img=#{headImg,jdbcType=BLOB}, </if> <if test="createTime!=null"> created_time=#{createTime,jdbcType=TIMESTAMP}, </if> id=#{id} where id=#{id} </update>
說明:1.這裡 id=#{id}是為了防止所有if都不滿足的時候語法錯誤。即使if中有個別滿足的,也不能省去,否則sql語法錯誤。
這種寫法不美觀,仍然然可以通過where標籤和set標籤來解決。
1.3 在INSERT動態插入列中使用if標籤
需求:如果某一列的引數值不為空,就使用傳入的值;如果傳入引數為空,就使用資料庫中預設的值(通常為空),而不使用傳入的空值。
(1)controller
1 @PostMapping("/insertUser") 2 public int insertUser(){ 3 4 SysUser sysUser=new SysUser(); 5 sysUser.setUserName("Tom"); 6 sysUser.setUserEmail("[email protected]"); 7 sysUser.setUserInfo("作家"); 8 return userService.insertUser(sysUser); 9 }View Code
(2)service實現類
1 @Override 2 public int insertUser(SysUser sysUser) { 3 return userMapper.insertUser(sysUser); 4 }View Code
(3)mapper介面
int insertUser(SysUser sysUser);
(4)mapper.xml
<insert id="insertUser"> insert into sys_user( user_name,user_password,user_email, <if test="userInfo!=null and userInfo!=''"> user_info, </if> head_img,created_time) values( #{userName},#{userPassword},#{userEmail}, <if test="userInfo!=null and userInfo!=''"> #{userInfo}, </if> #{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP}) </insert>
二. choose(when、otherwise)
if標籤只能實現if功能,沒有else功能。於是可以通過本節的組合來實現if..else的功能。choose中農包含when和otherwise兩個標籤,一個choose中至少有一個when,有0個或1個otherwise.
我的理解:when就相當於java中的else if,而otherwise就相當於java中的else。
需求:準備如下表。當ID有值的時候就優先採用ID進行查詢匹配使用者;如果ID沒有值,那就採用使用者名稱進行查詢匹配的使用者。
(1)controller
1 @PostMapping("/selectByIdOrName") 2 SysUser selectByIdOrName(){ 3 SysUser sysUser=new SysUser(); 4 sysUser.setId(1L); 5 sysUser.setUserName("test3"); 6 return userService.selectByIdOrName(sysUser); 7 }View Code
(2)service實現類
1 @Override 2 public SysUser selectByIdOrName(SysUser sysUser) { 3 return userMapper.selectByIdOrName(sysUser); 4 }View Code
(3)mapper介面
SysUser selectByIdOrName(SysUser sysUser);
(4)mapper.xml
<select id="selectByIdOrName" resultType="com.example.demo.dao.SysUser"> select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, created_time createTime from sys_user where 1=1 <choose> <when test="id!=null"> and id=#{id} </when> <when test="userName!=null and userName!=''"> and user_name=#{userName} </when> <otherwise> and 1=2 </otherwise> </choose> </select>
{
"id": 1,
"userName": "test1",
"userPassword": "123456",
"userEmail": "[email protected]",
"userInfo": "管理員",
"headImg": null,
"createTime": "2020-03-01"
}
三. where、set、trim
3.1 where標籤
修改之前的where 1=1例子,姓名模糊匹配,郵箱完全匹配查詢。
修改之前:
<select id="selectByUser" resultType="com.example.demo.dao.SysUser"> select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, created_time createTime from sys_user where 1=1 <if test="userName!=null and userName!=''"> and user_name like concat('%',#{userName},'%') </if> <if test="userEmail!=null and userEmail!=''"> and user_email=#{userEmail} </if> </select>
直接將xml檔案改為如下:
<select id="selectByUser" resultType="com.example.demo.dao.SysUser"> select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, created_time createTime from sys_user <where> <if test="userName!=null and userName!=''"> and user_name like concat('%',#{userName},'%') </if> <if test="userEmail!=null and userEmail!=''"> and user_email=#{userEmail} </if> </where> </select>
說明:當if都不滿足的時候,where中就沒有元素,就不會存在之前缺少where 1=1造成sql錯誤的問題。
3.2 set用法
還是之前的例子:
修改之前:
<update id="updateBySelective"> update sys_user set <if test="userName!=null and userName!=''"> user_name=#{userName}, </if> <if test="userPassword!=null and userPassword!=''"> user_password=#{userPassword}, </if> <if test="userEmail!=null and userEmail!=''"> user_email=#{userEmail}, </if> <if test="userInfo!=null and userInfo!=''"> user_info=#{userInfo}, </if> <if test="headImg!=null"> head_img=#{headImg,jdbcType=BLOB}, </if> <if test="createTime!=null"> created_time=#{createTime,jdbcType=TIMESTAMP}, </if> id=#{id} where id=#{id} </update>
修改之後:
1 <update id="updateUser"> 2 update sys_user 3 set 4 <foreach collection="_parameter" item="val" index="key" separator=","> 5 ${key}=#{val} 6 </foreach> 7 where id=#{id} 8 </update> 9 10 <update id="updateBySelective"> 11 update sys_user 12 <set> 13 <if test="userName!=null and userName!=''"> 14 user_name=#{userName}, 15 </if> 16 <if test="userPassword!=null and userPassword!=''"> 17 user_password=#{userPassword}, 18 </if> 19 <if test="userEmail!=null and userEmail!=''"> 20 user_email=#{userEmail}, 21 </if> 22 <if test="userInfo!=null and userInfo!=''"> 23 user_info=#{userInfo}, 24 </if> 25 <if test="headImg!=null"> 26 head_img=#{headImg,jdbcType=BLOB}, 27 </if> 28 <if test="createTime!=null"> 29 created_time=#{createTime,jdbcType=TIMESTAMP}, 30 </if> 31 id=#{id} 32 </set> 33 where id=#{id} 34 </update>View Code
這種只解決了逗號問題,不是很全面的解決問題,仍然需要
id=#{id}
3.3 trim標籤
where和set標籤的功能都能通過trim標籤實現。
舉例:
(1)還是之前的使用者名稱模糊匹配,郵箱完全匹配的例子:(使用trim標籤去除多餘的and關鍵字)
修改mapper.xml檔案:
<select id="selectByUser" resultType="com.example.demo.dao.SysUser"> select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, created_time createTime from sys_user <trim prefix="where" prefixOverrides="and"> <if test="userName!=null and userName!=''"> and user_name like concat('%',#{userName},'%') </if> <if test="userEmail!=null and userEmail!=''"> and user_email=#{userEmail} </if> </trim> </select>
效果一樣的。但是就不會多寫where1=1,並且指定了prefix為where。