0

0

mybatis 中#和$4}的区别是什么?

畫卷琴夢

畫卷琴夢

发布时间:2025-11-12 10:16:02

|

401人浏览过

|

来源于php中文网

原创

{}通过预编译防止SQL注入并提升性能,${}则直接字符串替换易引发安全风险;前者用于参数值,后者仅用于表名列名等需动态拼接的场景且必须严格校验。

mybatis 中#和$4}的区别是什么?

MyBatis里,#{}${} 的核心区别在于它们处理参数的方式:#{} 会将参数视为一个值,通过预编译(PreparedStatement)的方式安全地进行参数替换,有效防止SQL注入;而 ${} 则是直接的字符串替换,它会将传入的内容原样拼接到SQL语句中,虽然在某些特定场景下有用,但极易引发SQL注入风险。

解决方案

当你使用 #{} 语法时,MyBatis 会在底层为你的SQL语句生成一个 PreparedStatement 对象。想象一下,数据库接收到的查询语句中,参数的位置都是用问号 ? 占位的。比如,你写 SELECT * FROM users WHERE id = #{userId},MyBatis 会把它翻译成类似 SELECT * FROM users WHERE id = ?,然后把 userId 的值作为参数绑定到这个问号上。这种方式的好处是显而易见的:数据库在执行之前就已经确定了SQL语句的结构,它只关心 ? 后面跟着的是什么值,而不会把这个值当作SQL命令的一部分来解析。这就从根本上杜绝了恶意的SQL代码片段被注入执行的可能性。而且,数据库通常会对预编译的SQL语句进行优化,缓存执行计划,这对性能也是有益的。

${} 就完全是另一回事了。它就像一个简单的文本替换工具。你写 SELECT * FROM ${tableName} WHERE id = #{userId},如果 tableName 的值是 users,那最终执行的SQL就是 SELECT * FROM users WHERE id = ?。看起来好像没什么问题?但如果 tableName 的值是 users; DROP TABLE orders; 呢?那最终的SQL就会变成 SELECT * FROM users; DROP TABLE orders; WHERE id = ?。这下麻烦就大了,数据库可能会先执行 SELECT,然后紧接着就把你的 orders 表给删了。这就是典型的SQL注入。所以,除非你对传入的字符串有绝对的控制和严格的校验,否则使用 ${} 是非常危险的。它主要用于那些不能被参数化的SQL元素,比如表名、列名、排序字段(ORDER BY 后面的字段)等等。

什么时候应该使用 #{}?

绝大多数情况下,只要你传递的是一个数据值,一个需要被查询、插入、更新或删除的具体内容,你就应该无脑选择 #{}。这不仅仅是出于安全的考虑,更是MyBatis设计哲学的一部分。它帮你处理了数据类型转换、特殊字符转义等一系列繁琐的事情,让你能专注于业务逻辑本身。

举个例子,无论是用户的ID、姓名、年龄,还是商品的库存、价格,订单的状态,这些都是数据。当你需要根据这些数据进行筛选、更新或者插入时,#{} 就是你的不二之选。比如:




  INSERT INTO user (name, age) VALUES (#{name}, #{age})



  UPDATE user SET age = #{age} WHERE id = #{id}

你看,这里的 idnameage 都是具体的值。使用 #{},MyBatis 会自动帮你处理好它们的数据类型,比如 id 是整数,name 是字符串,它会以最安全的方式把它们传递给数据库。你几乎不需要担心什么,只管把参数传进去就行。这是一种规范,也是一种最佳实践,能让你的代码更健壮、更易于维护。

什么时候必须使用 ${}?它的潜在风险是什么?

既然 #{} 这么好,那为什么还需要 ${} 呢?这就是一个“不得不为之”的选择。有些SQL语句的组成部分,它本身就不是一个“值”,而是一个SQL关键字或者一个数据库对象的名字。比如,你想动态地指定查询的列名,或者动态地指定排序的字段和顺序。

考虑一个场景,你有一个通用的查询接口,用户可以指定按哪个字段排序,是升序还是降序。这时候,ORDER BY 后面的列名和 ASC/DESC 就不能用 #{} 了,因为它们不是数据,而是SQL语句的结构。





在这种情况下,columnNamesortOrder 必须用 ${} 来替换。因为数据库需要直接看到 ORDER BY name ASC 这样的完整字符串,而不是 ORDER BY ? ?

汉仪书宋一字体
汉仪书宋一字体

汉仪书宋一简是汉仪字库里面宋体的一种,与宋体字没什么区别,通常用于特殊提醒如批注中。

下载

但是,这里面的风险是巨大的,我前面也提到了。如果 columnName 传入的是 name; DROP TABLE user; 这样的恶意字符串,那么你的用户表可能就没了。

要规避这种风险,通常的做法是:

  1. 白名单校验: 在Java代码层面,严格校验传入的 ${} 参数。比如,如果 columnName 只能是 id, name, age 这三个之一,你就写个 if/else 或者 switch 来判断,只允许这些合法值通过。
  2. 避免用户直接输入: 尽量不要让用户直接输入这些会用 ${} 替换的参数,而是提供下拉框、单选按钮等方式,让他们选择预设好的合法值。

说实话,每次用到 ${} 我都会心里咯噔一下,然后立刻去检查有没有做严格的输入校验。这就像在代码里埋了个小地雷,虽然你知道它在哪儿,但总得小心翼翼地绕过去。

除了安全性,#{} 和 ${} 在性能上有什么差异吗?

除了安全性这个最核心的区别,#{}${} 在性能上确实也存在差异,这主要与数据库如何处理SQL语句有关。

当数据库收到一个SQL查询时,它通常会经历几个阶段:解析(parsing)、优化(optimization)、执行(execution)。

使用 #{} 时,MyBatis 会生成 PreparedStatement。这意味着SQL语句的结构是固定的,参数是独立的。数据库第一次收到这样的语句时,会对其进行解析和优化,生成一个执行计划(execution plan),然后将这个计划缓存起来。后续再执行相同的SQL语句(只是参数不同),数据库可以直接复用之前缓存的执行计划,省去了重复解析和优化的开销。这对于高并发、频繁执行的查询来说,能显著提升性能。数据库只需要把新的参数绑定到已经准备好的执行计划上就行了,效率自然更高。

${} 则不同。每次使用 ${} 拼接的SQL语句,对于数据库来说,都是一条全新的、从未见过的SQL语句。即使只有一小部分内容不同,数据库也认为这是一条全新的查询。因此,每次执行这样的SQL语句,数据库都需要重新进行解析、优化,并生成新的执行计划。这个过程虽然在单次查询中开销可能不明显,但在高并发或大量重复查询的场景下,这些额外的解析和优化开销就会累积起来,对数据库的CPU和内存造成不必要的负担,从而影响整体性能。

所以,从性能角度看,#{} 的预编译和参数绑定机制,使得数据库能够更高效地处理重复查询,减少了不必要的解析和优化开销,在多数情况下都优于 ${}${} 带来的性能损耗,虽然可能不如SQL注入的风险那么立竿见影,但长期来看,对系统稳定性和扩展性也是一个潜在的隐患。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

835

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

740

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

736

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.6万人学习

C# 教程
C# 教程

共94课时 | 6.9万人学习

Java 教程
Java 教程

共578课时 | 47.1万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号