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

相关推荐
麦聪聊数据6 分钟前
为何通用堡垒机无法在数据库运维中实现精准风控?
数据库·sql·安全·低代码·架构
2301_7903009611 分钟前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python
weixin_4997715512 分钟前
C++中的组合模式
开发语言·c++·算法
初级代码游戏12 分钟前
套路化编程 C# winform 自适应缩放布局
开发语言·c#·winform·自动布局·自动缩放
_waylau16 分钟前
鸿蒙架构师修炼之道-架构师的职责是什么?
开发语言·华为·harmonyos·鸿蒙
zfoo-framework20 分钟前
帧同步和状态同步
java
charlotte1024102423 分钟前
高并发:关于在等待学校教务系统选课时的碎碎念
java·运维·网络
2的n次方_27 分钟前
CANN Ascend C 编程语言深度解析:异构并行架构、显式存储层级与指令级精细化控制机制
c语言·开发语言·架构
m0_7369191027 分钟前
用Pandas处理时间序列数据(Time Series)
jvm·数据库·python
亓才孓28 分钟前
[JDBC]PreparedStatement替代Statement
java·数据库