01. MyBatis中 #{} 和 ${} 区别

1. 使用场景

动态 SQL:根据不同的条件拼接出不同的 SQL 语句。这样的 SQL 更灵活,也能适用更多的场景。

在 Mybatis 的 Mapper.xml 映射文件中编写 SQL 语句时,#{}${} 就是用来对引入的形参变量进行取值的。#{}${} 都可以用来对变量取值,但用法却有不同,需要格外注意。

2. #{}${} 的用法和区别

2.1 区别一

  • #{}:在解析变量时,会将变量的值取出,并自动给其添加引号,然后拼接到 SQL 语句中;
  • ${}:在解析变量时,直接将变量的值取出,然后直接拼接到 SQL 语句中。

假设,我要写一个 select 语句,定义了一个变量 name = “Pual”。当我用 #{} 拼接 SQL 时

	<select id="queryByName" parameterType="String" resultType="HashMap">
        SELECT * FROM user WHERE username=#{value}
    </select>

我们得到拼接的 SQL 为:

SELECT * FROM user WHERE username="Pual";

当我用 #{} 拼接 SQL 时,

	<select id="queryByName" parameterType="String" resultType="HashMap">
        SELECT * FROM user WHERE username=${value}
    </select>

我们得到拼接的 SQL 为:

SELECT * FROM user WHERE username=Pual;

这条语句在执行的时候会报错。可见,这种情况下我们是不能使用 ${} 拼接的。

2.2 区别二

  • ${}:直接将变量值和 SQL 拼接成完整的 SQL 语句后,再进行编译。
  • #{}:先用占位符代替参数将SQL语句先进行预编译,然后再将变量值替换进来。

因此,#{} 方式可以防止 SQL 注入问题。下面我们分析原因。

什么是 SQL 注入?

在使用 SQL 语句进行数据库操作时,如果对入参没有校验,那么攻击者就可以构造特殊的 SQL 语句,直接获取或修改数据库中的数据。

例如,我们有一个需求,给定了一个用户的姓名和密码,要求从用户表(user)中查询出该用户的信息。如果我们使用 ${} 的方式实现,即

	<select id="queryByName" parameterType="String" resultType="HashMap">
        SELECT * FROM user WHERE username='${username}' and password='${password}'
    </select>

我们正常传入一组数据:username=“pual”、password=“123456” 当然不会有问题。假如我是一个恶意攻击者,我可以构造一组参数:username=“pual’ or 1=1 #”,密码随意输一个"123",我们会得到

SELECT * FROM user WHERE username='pual' or 1=1 # and password='${password}'

这样,# 会将它后面的 SQL 注释掉,而 # 前面的 where 条件一直为 true,这样我就可以获取到所有用户的信息。

为什么 #{} 可以防止 SQL 注入

#{} 方式先用占位符代替参数,对 SQL 语句进行预编译后,再将参数中的内容替换到 SQL 中。由于 SQL 语句已经被预编译过,参数中的内容,无法变为 SQL 命令的一部分,攻击者也就无法再通过非法的参数去修改 SQL 命令了。

3. 只能使用 ${} 的场景

根据上面的例子,我们能看出,#{} 会给引用的变量加上引号,所以当我们的变量中要传入的是表名或者表的字段名时,这种情况下是不能使用 #{} 的,只能使用 ${}。例如

	<select id="queryByName" parameterType="String" resultType="HashMap">
        SELECT * FROM ${tableName} WHERE username="Pual"
    </select>

4. 总结

  • 当我们的变量中要传入的是表名或者表的字段名时,只能使用 ${}。其余场景下虽然 #{}${} 都适用,但更建议使用 #{},以防止 SQL 注入。
  • #{} 方式会进行预编译,参数是在编译之后填充进去的,所以不需要加上引号;
  • ${} 方式实现的是 SQL 语句的直接拼接,如果是需要添加引号的场景,需要子级手动在 SQL 中添加引号。
  • #{} 能预防 SQL 注入,${} 不能。
  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值