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标签来获取即可。

相关推荐
long3161 天前
K‘ 未排序数组中的最小/最大元素 |期望线性时间
java·算法·排序算法·springboot·sorting algorithm
欧阳x天1 天前
STL详解(九)—— stack和queue的模拟实现
开发语言·c++
xqqxqxxq1 天前
洛谷算法1-1 模拟与高精度(NOIP经典真题解析)java(持续更新)
java·开发语言·算法
DarkAthena1 天前
【GaussDB】排查创建索引后查询数据行数发生变化的问题
数据库·sql·gaussdb
MengFly_1 天前
Compose 脚手架 Scaffold 完全指南
android·java·数据库
沐知全栈开发1 天前
Rust 函数
开发语言
PPPPickup1 天前
application.yml或者yaml文件不显示绿色问题
java·数据库·spring
*小海豚*1 天前
springcloud项目运行启动类无法启动,IDEA也没有任何提示
java·ide
面对疾风叭!哈撒给1 天前
Windows 系统安装 Mysql 8.0+
数据库·windows·mysql
he___H1 天前
Redis高级特性
数据库·redis·缓存