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 分钟前
数据库:约束
数据库·mysql
小龙报3 分钟前
【Coze-AI智能体平台】低代码省时高效:Coze 应用开发全流程指南
java·人工智能·python·深度学习·低代码·chatgpt·交互
KmSH8umpK8 分钟前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第四篇
数据库·redis·分布式
念何架构之路17 分钟前
Go Web基础和Http演进
开发语言·后端·golang
勿忘初心122119 分钟前
【Java实战】SpringBoot 集成 freemarker 导出 Word 模板
java·spring boot·freemarker·模板引擎·word导出·后端实战
初心未改HD23 分钟前
Go语言database/sql与SQLx:构建健壮的数据访问层
开发语言·golang
绿草在线25 分钟前
SpringBoot项目实战:从零搭建高效开发环境
java·spring boot·后端
晚风吹红霞25 分钟前
C++异常处理核心知识点全解析
开发语言·c++
CoderCodingNo26 分钟前
【信奥业余科普】C++ 的奇妙之旅 | 17:面的铺展与文本的本质——二维数组与字符串
开发语言·c++
J2虾虾27 分钟前
Java Lambda 表达式详解文档
java·开发语言