当前位置: 首页 > 产品大全 > MyBatis探秘 #{}与${}参数传递差异解码——筑牢数据库交互之根基

MyBatis探秘 #{}与${}参数传递差异解码——筑牢数据库交互之根基

MyBatis探秘 #{}与${}参数传递差异解码——筑牢数据库交互之根基

在基于Java的持久层框架MyBatis中,#{}与${}是处理SQL语句时两种最为核心的参数占位符,它们虽然外观相似,但在底层处理机制、安全性和应用场景上却存在着本质的区别。正确理解并运用这两者,是构建高效、安全数据访问层的关键,也是数据库连接池等技术能够稳定、高效运行的重要前提。

一、核心机制差异:预编译与字符串拼接

#{}(参数占位符)
其工作原理是预编译(PreparedStatement)。MyBatis在解析SQL时,会将#{}替换为?,然后将SQL语句的编译和参数的传递分离。数据库驱动会先对SQL语句的结构进行编译和优化,再将具体的参数值安全地设置进去。这个过程能有效防止SQL注入,因为参数值会被视为数据而非SQL指令的一部分。例如:
`sql
SELECT FROM user WHERE id = #{userId}
`
会被处理为类似于SELECT </em> FROM user WHERE id = ?的预编译语句,然后将userId的实际值安全地传递。

${}(字符串替换符)
其工作原理是直接的字符串拼接。MyBatis在解析阶段,会直接将${}内的内容(通常是一个OGNL表达式求值结果)以字符串的形式替换到SQL语句的对应位置,生成一条完整的SQL语句,然后提交给数据库执行。例如:
`sql
SELECT FROM ${tableName} ORDER BY ${orderColumn}
`
如果tableName的值为"user"orderColumn的值为"create_time",则最终执行的SQL为:SELECT </em> FROM user ORDER BY create_time

二、安全性对比:SQL注入风险

这是两者最显著也最关键的差异。

  • #{} 高度安全:由于其预编译特性,用户输入的内容无论如何变化,都只会被当作参数值处理,无法改变原SQL语句的结构,因此从根本上杜绝了SQL注入攻击。
  • ${} 存在风险:由于是直接拼接,如果${}内的参数值来自不可信的用户输入(如前端表单),攻击者可以精心构造输入来改变SQL语义,导致数据泄露、篡改甚至删除。例如,对于SELECT <em> FROM user WHERE id = ${inputId},如果inputId被传入"1 OR 1=1",最终执行的SQL将变成SELECT </em> FROM user WHERE id = 1 OR 1=1,导致查询出所有用户数据。

安全准则绝大多数情况下,应优先使用#{}。只有在参数值明确安全、且需要动态改变SQL结构(非数据值)的场景下,才谨慎考虑使用${}。

三、适用场景剖析

#{} 的典型场景
1. WHERE条件中的值:这是最主要的使用场景,用于传递查询、更新、删除的条件值。
2. INSERT语句的VALUES值
3. UPDATE语句的SET值
简单来说,几乎所有传递具体数据值的地方都应使用#{}

${} 的适用场景(需谨慎)
1. 动态表名或列名:当SQL语句需要根据参数动态指定数据库表名或字段名时,因为这些内容是SQL结构的一部分,无法使用预编译的?占位。如上文的${tableName}例子。
2. ORDER BY 排序字段:需要根据前端选择动态排序时,如ORDER BY ${sortField} ${sortOrder}
3. SQL函数或特殊关键字:如使用数据库原生函数,如SELECT ${aggregateFunction}(column) FROM table

关键提醒:在使用${}时,必须确保参数值不是来自不可信的直接用户输入。最佳实践是,在服务端代码中通过白名单机制进行校验和映射,例如将前端传入的"sortByTime"映射为数据库列名"create_time",再传递给${}

四、与数据库连接池的协同

理解#{}${}的差异,对于充分发挥数据库连接池(如HikariCP, Druid等)的效能至关重要。

  1. 提升连接复用效率:预编译语句(#{}生成)是数据库连接池优化的重点。数据库驱动和服务器会对预编译语句进行缓存(Statement Caching)。当相同的SQL结构(仅参数值不同)反复执行时,数据库可以跳过语法解析和优化阶段,直接使用缓存的执行计划,极大提升了执行速度。连接池可以更好地管理和复用这些“已准备好”的语句句柄,减少数据库端的资源开销。
  2. 保障连接健康与安全:使用#{}避免了SQL注入,从而防止了因恶意SQL导致的数据库连接异常占用、资源耗竭或数据损坏,确保了连接池中每个连接的健康和稳定,维护了整个应用数据交互基石的牢固。
  3. ${}的潜在影响:滥用${}会导致每次SQL语句都可能不同(因为字符串内容变了),数据库无法有效缓存执行计划,降低了执行效率。注入风险可能导致数据库异常,间接影响连接池的稳定性和可用性。

###

#{}${}的选择,本质上是安全、性能与灵活性的权衡。

  • #{}默认且首选的方案,它安全、高效,能与数据库及连接池深度优化配合,是处理用户输入和业务数据的“安全卫士”。
  • ${}特定场景下的工具,它提供了动态SQL的灵活性,但必须由开发者在确保参数值绝对安全的前提下审慎使用,是处理SQL结构动态性的“手术刀”。

筑牢数据交互的根基,始于对每一个SQL语句细节的精准把控。正确使用#{}${},不仅是编写MyBatis代码的基本功,更是构建稳健、高性能数据持久层,让数据库连接池等基础设施发挥最大效能的基石。

更新时间:2026-04-04 16:40:40

如若转载,请注明出处:http://www.91ziji.com/product/24.html