MyBatis——动态SQL讲解

#{}和${}的区别

#{}的示例如下

${}的示例如下

如果这种情况下去测试上面的两个方法,那么用${}接受参数的方法会报错。

通过日志我们可以看出,由于password和userName是String类型,所以在查询的时候要加上引号才行。

而当我们用${}的方式来接收参数的时候,(这种方式称为即时SQL),这会直接把参数拼接到SQL语句中,不会添加引号,这就导致我们无法查询到相关数据。

而用#{}的方式来接受参数的时候,(这种方式称为预处理SQL),这种方式会采用占位的方式,并且也会识别我们传进来的参数类型,于是就不会报错。

解决办法,我们可以在SQL语句中手动添加引号:

这样就可以顺利执行了。

除此之外,${}还存在SQL注入问题:

SQL注入问题

下面我们先来看一下这2个SQL语句:

第二个SQL语句中我想传入的password参数是:lisi' or 1='1

但是这条SQL语句却把整个表中的数据都给查询出来了,这是因为我们传如的password这个参数的数值把我们事先定义好的SQL语句进行了修改,因为1='1'这个条件一定是正确的,所以就可以把所有的数据都查询出来了。

像这样通过传入的参数修改原先定义好的SQL语句的问题就叫做SQL注入问题:

如上图所示,这就是当使用${}来接收参数时,出现SQL注入问题的情况。

当我们把同样的参数放在用#{}来接受参数的方法中就不会出现SQL注入问题。

需要注意的是,当我们使用${}来接收参数的时候不一定会出现SQL注入的问题,具体还要看代码是如何书写的。

排序

使用#{}接收参数的形式来实现排序:

通过日志我们可以发现,这个方式并不行,原因是我们使用#{}来接收参数的时候,只要参数是字符串类型,都会加上'',但是asc或者desc却不需要加''。于是这个查询就无法完成。

解决该问题我们可以使用${}来接收参数:

这个时候我们就可以对查询到的结果进行排序:

模糊查询

如果我们使用#{}来接收参数仍然会报错,它实际执行的SQL如下:

此时我们也可以通过使用${}来接受参数的方式来解决这个问题:


但是由于使用${}来接收参数会存在SQL注入问题,于是我们可以使⽤MySql的内置函数 concat() 来处理,实现代码和运行截图如下:

if标签

XML 复制代码
 <insert id="insertUser3">
         insert into user_info (username,password,age,
        <if test="gender!=null">
            gender,
        </if>
        phone)
        VALUES(#{username},#{password},#{age},
        <if test="gender!=null">
            #{gender},
        </if>
        #{phone})
    </insert>

这个代码表示只有当在插入数据的时候传入了gender的值,才会在新增的数据中有gender这个属性,如果不传入,就是数据库中的默认值:

tirm标签

XML 复制代码
        <insert id="insertUser3">
        insert into user_info (
        <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>
        ) VALUES(
            <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>
    </insert>

由于我的测试用例中并没有传入username,所以这就会让SQL语句的password前面多出来一个,

接下来我们就通过tirm标签来解决这个问题:

标签中有如下属性:

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

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

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

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

XML 复制代码
 <trim prefixOverrides=",">
            <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>
XML 复制代码
 <trim prefixOverrides=",">
                <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>

我们可以对上面的两个板块使用改标签去掉开头的,

where标签

XML 复制代码
 <select id="selectBycondition" resultType="com.example.mybatis.model.UserInfo">
        select * from user_info
        <where>
            <if test="phone!=null">
                phone =#{phone}
            </if>
            <if test="deleteFlag!=null">
                and delete_flag=#{deleteFlag}
            </if>
        </where>
    </select>

当我们不传入任何参数的时候where标签会把上述SQL语句优化为全表查询,当有参数的时候,再根据参数的值来进行查询。

set标签

XML 复制代码
<update id="updateByCondition">
        update user_info
        <set>
            <if test="age!=null">
                age=#{age},
            </if>
            <if test="gender!=null">
                gender=#{gender}
            </if>
        </set>
        where id=#{id}
    </update>

foreach标签

java 复制代码
<delete id="batchDelete">
        delete from user_info where
        id in
<!--        (8,9,10)-->
        <foreach collection="list" open="(" close=")" item="ID" separator=",">
            #{ID}
        </foreach>
    </delete>

我们以上述代码为例,open表示我们要拼接的内容的开头是什么,close表示拼接的内容以什么为结尾,item则表示我们传入的集合中的每一个元素的变量名,separator表示元素与元素之间的分隔符,本案例中分隔符就是,index表示索引。

include标签

sql标签中放的是一些SQL语句,当后面我们的SQL语句中还需要用到这些语句的时候,直接通过include标签来获取即可。

相关推荐
@淡 定2 小时前
JVM调优参数配置详解
java·jvm·算法
撩得Android一次心动2 小时前
Android 四大组件——Service(服务)【基础篇2】
android·java·服务·四大组件·android 四大组件
爱宇阳2 小时前
在 Docker 环境中为 GitLab 实例配置邮件服务器
java·docker·gitlab
王柏龙2 小时前
c# aggregate使用
开发语言·c#
小鸡吃米…2 小时前
Python - 构造函数
开发语言·python
moonquakeTT2 小时前
C++:智能指针
开发语言·c++
hoiii1872 小时前
基于MATLAB实现无监督数据建模
开发语言·matlab
小丁努力不焦虑2 小时前
mysql八股文
数据库·mysql
大梦谁先觉i2 小时前
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
java·后端·spring