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
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
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
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
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
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
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
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
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
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
2
3
4
5
6
