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

相关推荐
想摆烂的不会研究的研究生18 分钟前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
码熔burning29 分钟前
MySQL 8.0 新特性爆笑盘点:从青铜到王者的骚操作都在这儿了!(万字详解,建议收藏)
数据库·mysql
毕设源码-郭学长35 分钟前
【开题答辩全过程】以 基于SpringBoot技术的美妆销售系统为例,包含答辩的问题和答案
java·spring boot·后端
故事不长丨35 分钟前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
猫头虎36 分钟前
2025最新OpenEuler系统安装MySQL的详细教程
linux·服务器·数据库·sql·mysql·macos·openeuler
梨落秋霜40 分钟前
Python入门篇【文件处理】
android·java·python
Java 码农1 小时前
RabbitMQ集群部署方案及配置指南03
java·python·rabbitmq
哈库纳玛塔塔1 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy2 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
S***q3772 小时前
Spring Boot管理用户数据
java·spring boot·后端