MyBatis — 动态 SQL

导读:本篇文章讲解 MyBatis — 动态 SQL,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

动态 SQL 使用

动态 sql 是 Mybatis 的强大特性之⼀,能够完成不同条件下不同的 sql 拼接。

可以参考官方文档:https://mybatis.org/mybatis-3/zh/dynamic-sql.html

可以通过这个配置在运行后看到对应还原出的 sql 语句:
在这里插入图片描述

1. <if> 标签

在注册用户的时候,可能会有这样⼀个问题,如下图所示:

在这里插入图片描述

注册分为两种字段:必填字段和非必填字段,那如果在添加⽤户的时候有不确定的字段传⼊,程序应该如何实现呢?
这个时候就需要使用动态标签 <if> 来判断了,比如添加的时候性别 sex 为非必填字段,具体实现如下:

    <insert id="insert" parameterType="org.example.model.User" useGeneratedKeys="true" keyProperty="id">
        insert into user(
        username,
        password,
        nickname,
        <if test="sex != null">
            sex,
        </if>
        birthday,
        head
        ) values (
        #{username},
        #{password},
        #{nickname},
        <if test="sex != null">
            #{sex},
        </if>
        #{birthday},
        #{head}
        )
    </insert>

(注意 test 中的 sex,是传入对象中的属性,不是数据库字段)

此时我们在接口方法中参数传 null,sql 语句就会忽略这个参数,最终传入数据库表后,这个字段为''(注意区分MySQL的 NULL 和 '')

如果不使用 动态 SQL,则需要构造很多的方法和实现,非常麻烦。

考虑一个极端情况:所有字段都是非必填项,这时我们没有办法控制最后一个属性后没有,(必须符合语法规范),怎么办呢?

2. <trim> 标签

之前的插入用户功能,只是有⼀个 sex 字段可能是选填项,如果所有字段都是⾮必填项,就考虑使用<trim>标签结合<if>标签,对多个字段都采取动态⽣成的方式。

<trim>标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

调整 UserMapper.xml 的插入语句为:

    <insert id="insert" parameterType="org.example.model.User" useGeneratedKeys="true" keyProperty="id">
        insert into user
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username != null">
                username,
            </if>
            <if test="password != null">
                password,
            </if>
            <if test="nickname != null">
                nickname,
            </if>
            <if test="sex != null">
                sex,
            </if>
            <if test="birthday != null">
                birthday,
            </if>
            <if test="head != null">
                head,
            </if>
            <if test="createTime != null">
                create_time,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="username != null">
                #{username},
            </if>
            <if test="password != null">
                #{password},
            </if>
            <if test="nickname != null">
                #{nickname},
            </if>
            <if test="sex != null">
                #{sex},
            </if>
            <if test="birthday != null">
                #{birthday},
            </if>
            <if test="head != null">
                #{head},
            </if>
            <if test="createTime != null">
                #{createTime},
            </if>
        </trim>
    </insert>

在以上 sql 动态解析时,会将第⼀个 <trim> 部分做如下处理:

  • 基于 prefix 配置,开始部分加上 (
  • 基于 suffix 配置,结束部分加上 )
  • 多个 <if> 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于 suffixOverrides 配置去掉最后⼀个 ,
  • 注意 <if test=“createTime != null”> 中的 createTime 是传入对象的属性;而 create_time 为数据库表的字段

3. <where> 标签

传入的用户对象,根据属性做 where 条件查询,用户对象中属性不为 null 的,都为查询条件。如 user.username 为 “a”,则查询条件为 where username=“a”:

UserMapper 接口中新增条件查询方法:

List<User> selectByCondition(User user);

UserMapper.xml 中新增条件查询 sql:

    <select id="selectByCondition" parameterType="org.example.model.User" resultMap="BaseResultMap">
        select id, username, password, nickname, sex, birthday, head, create_t
        ime
        from user
        <where>
            <if test="username != null">
                and username=#{username}
            </if>
            <if test="password != null">
                and password=#{password}
            </if>
            <if test="nickname != null">
                and nickname=#{nickname}
            </if>
            <if test="sex != null">
                and sex=#{sex}
            </if>
            <if test="birthday != null">
                and birthday=#{birthday}
            </if>
            <if test="head != null">
                and head=#{head}
            </if>
            <if test="createTime != null">
                and create_time=#{createTime}
            </if>
        </where>
    </select>

如果参数都传 null,那就是查询全部喽。

以上 <where> 标签也可以使⽤ <trim prefix="where" prefixOverrides="and"> 替换。
(也就是开始部分判断是否加 where;去掉第一个 and)

4. <set> 标签

根据传入的用户对象属性来更新用户数据,可以使用 <set> 标签来指定动态内容。

UserMapper 接口中修改用户方法:根据传入的用户 id 属性,修改其他不为 null 的属性:

int updateById(User user);

UserMapper.xml 中添加更新用户 sql:

    <update id="updateById" parameterType="org.example.model.User">
        update user
        <set>
            <if test="username != null">
                username=#{username},
            </if>
            <if test="password != null">
                password=#{password},
            </if>
            <if test="nickname != null">
                nickname=#{nickname},
            </if>
            <if test="sex != null">
                sex=#{sex},
            </if>
            <if test="birthday != null">
                birthday=#{birthday},
            </if>
            <if test="head != null">
                head=#{head},
            </if>
            <if test="createTime != null">
                create_time=#{createTime},
            </if>
        </set>
        where id=#{id}
    </update>

以上 <set> 标签也可以使用 <trim prefix="set" suffixOverrides=","> 替换。

5. <foreach> 标签

对集合进行遍历时可以使用该标签。<foreach> 标签有如下属性:

  • collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

示例:根据多个用户 id 来删除用户数据 (对应 sql 中的 in)。

UserMapper 中新增接口方法:

    // 多条用户的删除
    public int delByIds(List<Integer> ids);

UserMapper.xml 中新增删除 sql:

    <delete id="delByIds">
        delete from userinfo where id in
        <foreach collection="ids" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>

单元测试:

@SpringBootTest // 当前测试的上下文环境为 springboot
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;
    
    @Test
    void delByIds() {
        List<Integer> list = new ArrayList<>();
        list.add(8);
        list.add(9);
        list.add(10);
        int result = userMapper.delByIds(list);
        System.out.println("删除了:" + result);
    }
}

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118543.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!