1. 程式人生 > 實用技巧 >Mybatis中的動態SQL在xml中支援的幾種常用標籤

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  @Override
2 public List<SysUser> selectByUser(SysUser sysUser) { 3 return userMapper.selectByUser(sysUser); 4 }
View Code

(3)mapper介面

List<SysUser> selectByUser(SysUser sysUser);

(4)mapper.xm<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>

說明: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。