当前位置: 首页 > article >正文

MyBatis中 #{} 和 ${} 区别

文章目录

  • 1. 使用场景
  • 2. `#{}` 和 `${}` 的用法和区别
    • 2.1 区别一
    • 2.2 区别二
      • 什么是 SQL 注入?
      • 为什么 `#{}` 可以防止 **SQL 注入**?
  • 3. 只能使用 `${}` 的场景
  • 4. 总结

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 注入,${} 不能。

http://www.kler.cn/a/271579.html

相关文章:

  • 【huawei】云计算的备份和容灾
  • QT串口通信,实现单个温湿度传感器数据的采集
  • python | OpenCV小记(一):cv2.imread(f) 读取图像操作(待更新)
  • android 圆形弹窗摄像头开发踩坑——源码————未来之窗跨平台操作
  • python算法和数据结构刷题[2]:链表、队列、栈
  • 机器人抓取与操作概述(深蓝)——1
  • Python实战:NumPy数组与矩阵操作入门
  • 提高安全投资回报:威胁建模和OPEN FAIR™风险分析
  • 数据类型【mysql数据库】
  • 数据可视化-ECharts Html项目实战(2)
  • 【Python循环3/5】条件循环语句
  • SeAndroid 安全策略机制
  • 基于单片机的智能小车泊车系统设计
  • Prompt Engineering(提示工程)
  • Rust的async和await支持多线程运行吗?
  • Unity Timeline学习笔记(2) - PlayableTrack
  • python二级备考(3)-综合应用
  • 【设计模式】Java 设计模式之组合模式(Composite)
  • 爱奇艺 CTR 场景下的 GPU 推理性能优化
  • 什么是http?
  • 【JAVA】JAVA方法的学习和创造
  • 后端系统开发之——创建SpringBoot工程
  • 比特币,区块链及相关概念简介(三)
  • 【Python爬虫+JAVA】采集电商平台数据信息|淘宝|京东|1688|抖音数据返回
  • ChatGPT团队:介绍OpenAI团队生产力提升工具
  • Python Web开发记录 Day9:Django part3 用户管理