【MyBatis】#{ } 和 ${ } 的区别

#{ } 和 ${ } 的区别

#{ }:预编译处理。
${ }:字符直接替换。

预编译处理是指:MyBatis 在处理 #{ } 时,会将 SQL 中的 #{…} 替换为 ? 号,使⽤ PreparedStatement 的 set ⽅法来赋值。
直接替换:是MyBatis 在处理 ${ } 时,就是把 ${ } 直接替换成变量的值。

  1. 定义不同: #{ } 是预处理, ${ } 是直接替换
  2. 安全性不同: #{ } 没有安全问题, ${ } 有 SQL 注入问题
  3. 使用场景不同: #{ } 适用于所有类型的参数匹配, 但是 ${ } 只使用于数值类型和关键字

#{ } 使用场景

  • 使用 #{ }
    <insert id="add">
        insert into userinfo(username,password,photo,state)
        values(#{username},#{password},#{photo},1)
    </insert>
==>  Preparing: insert into userinfo(username,password,photo,state) values(?,?,?,1)
==> Parameters: zhaoliu(String), 666(String), img.png(String)
<==    Updates: 1

先将 参数的位置替换为 ? 然后再把对应类型的参数填入进去.

  • 使用 ${ }
    <insert id="add">
        insert into userinfo(username,password,photo,state)
        values(${username},${password},${photo},1)
    </insert>
==>  Preparing:insert into userinfo(username,password,photo,state) values(zhaoliu,666,img.png,1)
==> Parameters: 

直接替换上了,所以 Parameters 为空, 替换时也不加 引号, 所以会插入失败

like 查询使用 #{ } 报错

    <select id="findUserByName" resultType="com.example.springboot3.model.User">
        select * from userinfo where username like '%#{username}%';
    </select>

相当于:

select * from userinfo where username like '%'username'%' 

所以代码报错

这个是不能直接使⽤ ${ },可以考虑使⽤ mysql 的内置函数 concat() 来处理

concat('a', 'b', 'c')  ==> 'abc'

实现代码如下:

    <select id="findUserByName" resultType="com.example.springboot3.model.User">
        select * from userinfo where username like concat('%', #{username}, '%');
    </select>
==>  Preparing: select * from userinfo where username like concat('%', ?, '%');
==> Parameters: zhaoliu(String)
<==    Columns: id, username, password, photo, createtime, updatetime, state
<==        Row: 7, zhaoliu, 666, img.png, 2023-10-09 11:29:00.0, 2023-10-09 11:29:00.0, 1
<==      Total: 1

${ } 的使用场景

关键字的替换, 比如排序

    <select id="getAll" resultType="com.example.springboot3.model.User">
        select * from userinfo order by id ${rule}
    </select>
==>  Preparing: select * from userinfo order by id desc
==> Parameters: 

使⽤ ${ } 可以实现排序查询,⽽使⽤ #{ } 就不能实现排序查询了,当使⽤ #{ } 查 询时,如果传递的值为 String 则会加单引号,就会导致 sql 错误。

所以:当传递的是一个 SQL 关键字时, 只能使用 ${ }

SQL 注入问题

假如我们真的使用了 ${ }, 那么因为我们知道 ${ } 是直接替换, 不会 加引号, 那么我们就会自己加上引号, 比如下面:

    <select id="isLogin" resultType="com.example.springboot3.model.User">
        select * from userinfo where username='${name}' and password='${pwd}'
    </select>

但是, 这样会引入一个很大的安全问题: SQL 注入问题

sql 注入代码关键部分:

"' or 1='1"

调用接口进行测试:

        List<User> list = userMapper.isLogin("afeagdee445", "' or 1 = '1");
        if (list.size() > 0) {
            System.out.println("登录成功");
        }

查看结果:

==>  Preparing: select * from userinfo where username='afeagdee445' and password='' or 1 = '1'
==> Parameters: 
<==    Columns: id, username, password, photo, createtime, updatetime, state
<==        Row: 1, admin, admin, , 2021-12-06 17:10:48.0, 2021-12-06 17:10:48.0, 1
<==        Row: 2, mysql, mysql, img.png, 2023-10-08 15:09:07.0, 2023-10-08 15:09:07.0, 1
<==        Row: 3, mysql, mysql, img.png, 2023-10-08 15:24:24.0, 2023-10-08 15:24:24.0, 1
<==        Row: 4, mysql, mysql, img.png, 2023-10-08 15:24:50.0, 2023-10-08 15:24:50.0, 1
<==        Row: 5, mysql, mysql, img.png, 2023-10-08 15:25:59.0, 2023-10-08 15:25:59.0, 1
<==        Row: 6, mysql, mysql, img.png, 2023-10-08 15:26:40.0, 2023-10-08 15:26:40.0, 1
<==        Row: 7, zhaoliu, 666, img.png, 2023-10-09 11:29:00.0, 2023-10-09 11:29:00.0, 1
<==      Total: 7
登录成功

登录成功了.
也就是说, 我们什么都不知道, 只要使用 SQL 注入就能得登录成功

由打印的 SQL 日志 我们就能看出来原因了

select * from userinfo where username='afeagdee445' and password='' or 1 = '1'

拼接出来的这个 SQL 的判断条件一定为 true, 因为最后是一个 or 1 = ‘1’, 这一定是 true 的.

但如果使用 #{ } 就不会有问题了

==>  Preparing: select * from userinfo where username=? and password=?
==> Parameters: afeagdee445(String), ' or 1 = '1(String)
<==      Total: 0

它这个等价于:

select * from userinfo where username='afeagdee445' and password="' or 1 = '1"

这里面单引号和双引号并不会匹配上

结论:⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式。
当不得不使用 ${ } 时,在业务代码中一定要对传递的值进行校验.

好啦! 以上就是对 #{ } 和 ${ } 区别 的讲解,希望能帮到你 !
评论区欢迎指正 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值