MyBatis 操作数据库(构造动态 SQL)

前言

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

<if> 标签

我们在填写用户信息的时候经常会看到如下的界面,用户信息中包含必填信息和非必填信息,非必填信息是填和不填都可以的,那这样的话插入到数据库中的数据有多种情况,SQL 语句也有多种情况,比如地址管理,我可以选择填,也可以选择不填,那么 SQL 语句的插入语句就要对应插入或者不插入

要想完成这个效果,我们就需要构造动态 SQL

接口定义:

java 复制代码
//通过用户提供的数据,动态构造 SQL 语句进行插入
Integer insertUserByCondition(UserInfo userInfo);

Mapper.xml实现:

java 复制代码
<insert id="insertUserByCondition">
        insert into userinfo
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="username!=null">
                    username,
                </if>
                <if test="password!=null">
                    password,
                </if>
                <if test="age!=null">
                    age,
                </if>
                <if test="gender!=null">
                    gender,
                </if>
                <if test="phone!=null">
                    phone
                </if>
            </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                #{username},
            </if>
            <if test="password!=null">
                #{password},
            </if>
            <if test="age!=null">
                #{age},
            </if>
            <if test="gender!=null">
                #{gender},
            </if>
            <if test="phone!=null">
                #{phone}
            </if>
        </trim>
    </insert>

<if> 标签的 test 属性表示判断的内容,如下的代码,判断参数 username 的值是否为 null,相当于判断用户是否输入 username,如果不为 null,说明用户输入了 username ,就需要插入数据到 username 字段,所以拼接 username, 到 SQL 语句中

java 复制代码
<if test="username!=null">
    username,
</if>

如果所有的参数都赋了值,构造的 SQL 语句就是:

java 复制代码
insert into userinfo( username, password, age, gender, phone )
values(#{username},#{password},#{age},#{gender},#{phone});

如果参数 gender 和 phone 都没赋值,就是:

java 复制代码
insert into userinfo( username, password, age)
values(#{username},#{password},#{age});

构造的 SQL 语句是根据用户的输入动态改变的

<trim> 标签

在上面 Mapper.xml 实现的代码中,我们用到了 <trim> 标签

标签中有如下属性:

• prefix:表⽰整个语句块,以prefix的值作为前缀

• suffix:表⽰整个语句块,以suffix的值作为后缀

• prefixOverrides:表⽰整个语句块要去除掉的前缀

• suffixOverrides:表⽰整个语句块要去除掉的后缀

在上面 Mapper.xml 实现的代码中,我们使用了<trim> 标签进行了以下处理

• 基于 prefix 配置,开始部分加上 (

• 基于suffix 配置,结束部分加上 )

• 多个组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于 suffixOverrides 配置去掉最后⼀个 ,

<where> 标签

<where> 标签只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的 AND 或 OR

看下⾯这个场景, 系统会根据我们的筛选条件, 动态组装 select 语句的 where 条件,来查询到我们指定的内容

假设所有的参数都输入,我们得到的 SQL 语句如下:

java 复制代码
SELECT id,username,password,age,gender,phone,delete_flag,create_time,update_time 
FROM userinfo 
WHERE id = #{id}
AND username = #{username} 
AND gender = #{gender};

接口定义:

java 复制代码
 //通过用户提供的数据,动态构造 SQL 语句进行查询
List<UserInfo> selectByCondition(UserInfo userInfo);

Mapper.xml实现:

java 复制代码
    <select id="selectByCondition" resultType="com.example.springbootdemo.dao.UserInfo">
        select id,username,password,age,gender,phone,delete_flag,create_time,update_time
        from userinfo
        <where>
            <if test="id!=null">
                and id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
            <if test="gender!=null">
                and gender=#{gender}
            </if>
        </where>
    </select>

假设用户一个参数都没有输入,得到的 SQL 语句就是:

java 复制代码
select id,username,password,age,gender,phone,delete_flag,create_time,update_time
from userinfo;

假设用户没有输入 id 参数,得到的 SQL 语句就是:

java 复制代码
SELECT id,username,password,age,gender,phone,delete_flag,create_time,update_time 
FROM userinfo 
WHERE username = #{username} 
AND gender = #{gender};

<set>标签

<set>标签动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号.(⽤于update语句中)

根据用户传入的参数,动态构造 SQL 语句,插入相关内容

接⼝定义:根据传⼊的用户 id 属性,修改其他传入参数的属性

java 复制代码
//通过用户提供的数据,动态构造 SQL 语句进行修改
Integer updateByCondition(UserInfo userInfo);

Mapper.xml实现:

java 复制代码
    <update id="updateByCondition">
        update userinfo
        <set>
            <if test="username!=null">
                username=#{username},
            </if>
            <if test="age!=null">
                age=#{age},
            </if>
            <if test="deleteFlag!=null">
                delete_flag=#{deleteFlag}
            </if>
        </set>
        where id=#{id}
    </update>

<foreach> 标签

对集合进⾏遍历时可以使⽤该标签。

标签有如下属性:

• collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象

• item:遍历时的每⼀个对象

• open:语句块开头的字符串

• close:语句块结束的字符串

• separator:每次遍历之间间隔的字符串

有以下场景我们将要删除的用户 id 都集中放到一个 List<Integer> 列表当中,在删除的时候,将列表中的用户 id 所指向的信息都进行删除

假设列表当中的数据为{1,2,3,4,5},我们要构造的 SQL 语句就应该为:

java 复制代码
delete from userinfo where id in(1,2,3,4,5);

接口定义:

java 复制代码
//给定一个 id 集合,将集合中的所有 id 对应的用户数据都删除
Integer deleteByIds(List<Integer> ids);

Mapper.xml实现:

java 复制代码
    <delete id="deleteByIds">
        delete from userinfo
               where id in
                     <foreach collection="ids" item="id" separator="," open="(" close=")">
                         #{id}
                     </foreach>
    </delete>

根据一开始提到的例子,我们通过 <foreach> 标签要构造出来的 SQL 结构应该为 (1,2,3,4,5),1,2,3,4,5 要通过遍历集合中的内容获得、

collection="ids" 表示绑定了参数中的集合 ids

item="id" 表示遍历集合得到的数据放到 id 中,通过 id 来使用

separator="," 遍历集合得到的数据之间通过 , 进行分割

open="(" <foreach> 标签包含的语句块以 "(" 作为开头

close=")" <foreach> 标签包含的语句块以 ")" 作为结尾

<sql> 和 <include> 标签

在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码

我们可以通过 <sql> 标签提取重复的 SQL 片段进行封装,通过 <include> 标签引用封装好的 SQL 片段

通过 <sql> 标签封装:

通过 id 属性为封装的 SQL 片段命名,方便后续进行调用

java 复制代码
<sql id="allColumn">
    id,username,password,age,gender,phone,delete_flag,create_time,update_time
</sql>

通过 <include> 标签引用:

通过 refid 属性设置要引入的 SQL 片段

java 复制代码
    <select id="selectByCondition2" resultType="com.example.springbootdemo.dao.UserInfo">
        select 
            <include refid="allColumn"></include>
            from userinfo
    </select>

最终得到的 SQL 语句为:

java 复制代码
select id,username,password,age,gender,phone,delete_flag,create_time,update_time
from userinfo;
相关推荐
尘浮生17 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君31 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队40 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
郑祎亦41 分钟前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
inventecsh1 小时前
mongodb基础操作
数据库·mongodb
白云如幻1 小时前
SQL99版链接查询语法
数据库·sql·mysql
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database
The_Ticker2 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Elastic 中国社区官方博客3 小时前
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
企鹅侠客3 小时前
ETCD调优
数据库·etcd