MyBatis动态SQL

2024/1/12 MyBatis框架

动态 SQL 是 MyBatis 的强大特性之一。可以根据不同条件拼接 SQL ,让我们将关注点在业务上,拼接SQL体现了易用性。

# 1、if

条件满足,拼接条件

Mapper接口新增方法

List<UserPO> selectUserByName3(@Param("name") String name);
1

Mapper.xml映射

<select id="selectUserByName3" resultType="com.xygalaxy.pojo.UserPO">
    select * from user where 1=1
    <if test="name!=null and name!=''">
        and username like CONCAT('%', #{name}, '%')
    </if>
</select>
1
2
3
4
5
6

测试

@Test
public void testExecutorInterceptor(){
    List<UserPO> userPOList = userMapper.selectUserByName3("");
    log.info("userPOList ==> "+userPOList);

    List<UserPO> userPOList2 = userMapper.selectUserByName3("ls");
    log.info("userPOList2 ==> "+userPOList2);
}
1
2
3
4
5
6
7
8

测试结果

  • test 中为条件表达式
  • if拼接语句中的and,如果多余了,会自动去掉,比如第一个条件时,前面是不加and的,if标签会自动去掉

# 2、choose、when、otherwise

多个条件选择一个,类似Java中的switch

<select id="selectUserBy" resultType="com.xygalaxy.pojo.UserPO">
    select * from user where 1=1
    <choose>
        <when test="id!=null and id!=''">
            and id = #{id}
        </when>
        <when test="name!=null and name!=''">
            and username like CONCAT('%', #{name}, '%')
        </when>
        <otherwise test="sex!=null and sex!=''">
            and sex = #{sex}
        </otherwise>
    </choose>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

条件满足when时,拼接条件后,如果都不满足,则拼接最后一个otherwise中的条件。

# 3、trim、where、set

  • where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="selectUserByName3" resultType="com.xygalaxy.pojo.UserPO">
    select * from user
    <where>
        <if test="name!=null and name!=''">
            and  username like CONCAT('%', #{name}, '%')
        </if>
    </where>
</select>
<!--
拼接结果:  select * from user where username like CONCAT('%', #{name}, '%')
-->
1
2
3
4
5
6
7
8
9
10
11
  • trim 元素来定制拼接
<select id="selectUserByName3" resultType="com.xygalaxy.pojo.UserPO">
    select * from user
    <trim prefix="where (" suffix=")" prefixOverrides="AND |OR ">
        <if test="name!=null and name!=''">
            and username like CONCAT('%', #{name}, '%')
        </if>
    </trim>
</select>

<!--
拼接结果:  select * from user where ( username like CONCAT('%', #{name}, '%') )
-->
1
2
3
4
5
6
7
8
9
10
11
12

  • prefix属性表示要添加到SQL语句前面的字符串。在这个案例中,我们指定了一个左括号where (作为前缀。
  • suffix属性表示要添加到SQL语句后面的字符串。在这个案例中,我们指定了一个右括号)作为后缀。
  • prefixOverrides属性是一个正则表达式,用于删除SQL语句中指定的前缀。在这个案例中,我们使用了AND |OR,表示删除以AND或者OR开头的字符串。
  • set用于动态更新语句的解决方案
<update id="updateUserById">
  update user
    <set>
        <if test="username != null">username=#{username},</if>
        <if test="password != null">password=#{password},</if>
        <if test="email != null">email=#{email},</if>
    </set>
  where id=#{id}
</update>

<!-- 当然也可以用trim来实现,suffixOverrides用于删除最后一个, -->
<update id="updateUserById">
  update user
    <trim prefix="SET" suffixOverrides=",">
        <if test="username != null">username=#{username},</if>
        <if test="password != null">password=#{password},</if>
        <if test="email != null">email=#{email},</if>
    </trim>
  where id=#{id}
</update>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4、foreach

对集合进行遍历(尤其是在构建 IN 条件语句的时候)

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT * FROM user
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

<!-- 
list传入为:1,2,3,4,5
拼接结果: SELECT * FROM user where ID in (1,2,3,4,5)
 -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14

  • collection:传入的集合
  • item:每一项遍历的值,index为集合索引下标
  • open:开始拼接的字符串
  • separator:每一项之间的分隔符
  • close:结束拼接的字符串

# 6、script

注解的映射器接口类中使用动态 SQL时使用

@Update({"<script>",
    "update user",
    "  <set>",
    "    <if test='username != null'>username=#{username},</if>",
    "    <if test='password != null'>password=#{password},</if>",
    "    <if test='email != null'>email=#{email},</if>",
    "  </set>",
    "where id=#{id}",
    "</script>"})
void updateUserById(UserPO userPO);
1
2
3
4
5
6
7
8
9
10

# 7、bind

创建变量,绑定到当前的上下文

<select id="selectUserByName2" resultType="com.xygalaxy.pojo.UserPO">
    select * from user
    <where>
        <bind name="currentName" value="'%'+name+'%'"/>
        username like #{currentName}
    </where>
</select>
1
2
3
4
5
6
7

# 8、selectKey

查询插入主键

<insert id="saveUser" parameterType="com.xygalaxy.pojo.UserPO">
    <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
        select if(max(id) is null, 1, max(id) +1) as id from user
    </selectKey>
    insert into user(id,username,password,email) values(#{id},#{username},#{password},#{email})
</insert>
1
2
3
4
5
6