讲师中心 微信公众号
AI工具推荐 视频效率加速

#{} 和 ${} 在 MyBatis 中有什么区别?

老婷姑娘_9524

老婷姑娘_9524

发布时间:2025-09-03 15:09:01

|

955人浏览过

|

来源于php中文网

原创

答案:#{}通过预编译防止SQL注入,安全且性能好,应优先使用;${}为字符串替换,存在注入风险,仅用于动态表名列名等必要场景。

#{} 和 ${} 在 mybatis 中有什么区别?

#{}
和
${}
在 MyBatis 中处理 SQL 参数的方式截然不同,核心区别在于
#{}
会进行预编译和参数绑定,从而有效防止 SQL 注入,而
${}
则是直接的字符串替换,存在潜在的安全风险,但对于某些动态 SQL 结构又是不可或缺的。

解决方案

在 MyBatis 中,

#{}
语法用于将参数值作为 JDBC
PreparedStatement
的参数进行设置。这意味着 MyBatis 会在执行 SQL 语句前,先将 SQL 模板发送到数据库进行编译,然后将参数值安全地绑定到预留的位置上。这个过程会自动处理参数的类型转换和转义,极大地增强了安全性,有效杜绝了 SQL 注入攻击。

举个例子,如果你写:

SELECT * FROM users WHERE id = #{userId}

当

userId
的值为
123
时,实际发送给数据库的可能是一个预编译语句,类似
SELECT * FROM users WHERE id = ?
,然后将
123
作为参数绑定到
?
上。如果
userId
的值为
1 OR 1=1
,它也会被当作一个普通的字符串值来处理,而不是作为 SQL 逻辑的一部分。

而

${}
语法则是将参数值直接拼接到 SQL 字符串中。它不会进行预编译和参数绑定,而是简单地将变量的值替换到 SQL 语句中。这意味着,如果参数值包含恶意 SQL 代码,这些代码就会直接成为最终执行的 SQL 语句的一部分,从而引发 SQL 注入漏洞。

例如,如果你写:

SELECT * FROM users ORDER BY ${columnName}

当

columnName
的值为
user_name
时,最终执行的 SQL 是
SELECT * FROM users ORDER BY user_name
。但如果
columnName
的值是
user_name; DROP TABLE users;
,那么整个 SQL 语句就会变成
SELECT * FROM users ORDER BY user_name; DROP TABLE users;
,后果不堪设想。

因此,我的个人建议是,除非你非常清楚自己在做什么,并且已经采取了严格的输入验证和白名单机制,否则,在任何需要传递用户输入数据的地方,都应该优先使用

#{}
。
${}
的使用场景非常有限,通常只在需要动态拼接表名、列名或者
ORDER BY
子句等 SQL 结构本身时才考虑。

SQL 注入的风险与防范:为什么选择 #{}?

在我看来,SQL 注入是后端开发中最常见的,也是最危险的安全漏洞之一。它就像是数据库的大门,如果你不加防范,攻击者就能通过这个漏洞,像开锁一样,随意进出你的数据宝库,轻则数据泄露,重则数据被篡改甚至删除。选择

#{}
,很大程度上就是为了关上这扇门。

#{}
之所以能防范 SQL 注入,关键在于它的工作机制。当 MyBatis 遇到
#{}
占位符时,它会告诉 JDBC 驱动:“嘿,这里有个参数,别把它当成 SQL 语句的一部分,把它当作一个普通的值来处理。” 数据库接收到这样的指令后,就会严格区分 SQL 语句的结构和参数数据。哪怕你的参数值里包含了
OR 1=1
这样的 SQL 关键字,数据库也只会把它当作一个普通的字符串,而不是额外的条件或命令。

想象一下,你有一个登录接口,用户输入用户名和密码。如果你的 SQL 是这样写的:

SELECT * FROM users WHERE username = '${username}' AND password = '${password}'

一个恶意用户在用户名输入框里填入

' OR '1'='1
,密码随便填。那么最终的 SQL 就会变成:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '随便填'

因为

OR '1'='1'
永远为真,这个查询就会返回所有用户的数据,绕过了密码验证。这简直是灾难。

word报告自动生成神器
word报告自动生成神器

Word报告自动生成神器。自动生成专业Word文档报告,支持模板填充、目录生成、表格/图表插入、页眉页脚、多级标题、样式主题、批量邮件合并。当用户需要生成Word报告、创建合同文档、批量生成通知/证书、填充Word模板、制作商业计划书时触发。

下载

但如果使用

#{}
:

SELECT * FROM users WHERE username = #{username} AND password = #{password}

即使恶意用户输入同样的内容,数据库也会将其视为字面量字符串,比如

username = '' OR '1'='1'
会被当成一个整体的用户名字符串去匹配,自然找不到对应用户,从而避免了注入。所以,从安全角度出发,
#{}
几乎是默认且必须的选择。

何时必须使用 ${}:动态SQL的边界与挑战

编程世界里哪有绝对的非黑即白呢?虽然

#{}
是安全的首选,但总有些场景是它力所不能及的,这时候
${}
就不得不登场了。这些场景通常涉及到 SQL 语句的结构本身需要动态变化,而不是仅仅参数值变化。

最典型的例子就是动态的表名、列名,以及

ORDER BY
子句。比如说,你的系统可能需要根据不同的业务场景查询不同的日志表(
log_2023
、
log_2024
),或者用户可以自定义报表显示的列和排序方式。

假设你需要根据用户选择的列进行排序:

<!-- 错误且危险的写法,但演示了需求 -->
SELECT * FROM products ORDER BY ${sortByColumn} ${sortOrder}

这里

sortByColumn
可能是
price
或
name
,
sortOrder
可能是
ASC
或
DESC
。
#{}
无法直接替换 SQL 关键字或标识符,因为它们是 SQL 结构的一部分,而不是数据。如果你尝试用
#{}
来替换
columnName
,MyBatis 会把
columnName
当成一个字符串值,并在其两边加上引号,导致 SQL 语法错误,比如
ORDER BY 'price'
,这显然不是我们想要的。

所以,在这种情况下,使用

${}
是唯一的选择。但这也带来了巨大的挑战:你必须自己承担起参数的验证和过滤责任。这意味着,你不能直接把用户输入的任何字符串扔进
${}
。你需要在代码层面,对
sortByColumn
和
sortOrder
进行严格的校验,比如:

  • 白名单机制:只允许预定义的一组安全值通过。例如,
    sortByColumn
    只能是
    id
    ,
    name
    ,
    price
    中的一个;
    sortOrder
    只能是
    ASC
    或
    DESC
    。
  • 避免直接拼接用户输入:永远不要让用户直接控制
    ${}
    中的内容。

这其实是个两难,你为了实现动态性而牺牲了安全性,所以在使用

${}
的地方,务必加倍小心,将其视为潜在的安全热点,并进行额外的安全审查。

性能与可维护性考量:除了安全,还有什么不同?

除了最显著的安全差异,

#{}
和
${}
在性能和代码可维护性方面也存在不小的区别,这些都是我们在实际开发中需要深思熟虑的。

从性能上看,

#{}
通常会带来更好的表现。由于它使用
PreparedStatement
,数据库可以对预编译的 SQL 语句进行缓存。当相同的 SQL 模板被多次执行,只是参数不同时,数据库可以直接使用缓存的执行计划,省去了每次解析、编译 SQL 的开销。这对于高并发、频繁执行的查询来说,性能提升是相当可观的。而
${}
每次都会生成一个全新的 SQL 字符串,数据库每次都需要重新解析和编译,这意味着每次执行都是一次“全新”的查询,无法享受到预编译带来的性能红利。

再聊聊可维护性。使用

#{}
的 SQL 语句通常更清晰、更易读。参数的占位符清晰地表明了哪些部分是动态数据,哪些是固定的 SQL 结构。这让其他开发者(包括未来的你)在阅读代码时,能一眼看出 SQL 的意图,也更容易进行调试。

反观

${}
,如果使用不当,或者动态拼接的逻辑过于复杂,生成的 SQL 语句可能会变得非常难以理解和调试。想象一下,一个复杂的条件查询,里面混杂了多个
${}
,再加上各种字符串拼接,最终生成的 SQL 语句可能面目全非,一旦出现问题,排查起来简直是噩梦。而且,
#{}
还会自动处理参数的类型转换,你不需要担心字符串、数字、日期之间的转换问题;而
${}
则需要你手动确保拼接进去的值是数据库能够接受的正确格式,否则很容易出现类型不匹配的错误。

所以,在选择使用哪种方式时,我们不仅要考虑眼前的功能实现,更要着眼于项目的长期健康发展,包括安全性、性能和未来的维护成本。在我看来,

#{}
是默认且推荐的姿势,而
${}
则是需要谨慎对待的“高级技巧”,用得好能解决特定问题,用不好则会埋下巨大的隐患。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

4603

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

951

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

1209

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

6581

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

3343

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

6560

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

9001

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

1230

2024.04.29

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

40

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
光速学会docker容器
光速学会docker容器

共33课时 | 3万人学习

vue-cli4商城项目案例
vue-cli4商城项目案例

共12课时 | 4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn