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

MyBatis中的#{}与${}的区别和应用详解

MyBatis中的#{}与${}的区别和应用详解

在使用MyBatis进行数据库操作时,经常会用到动态SQL语句。为了动态地拼接SQL,MyBatis提供了两种占位符方式:#{} 和 ${}。这两者有着不同的用法和特性,在实际开发中需要根据具体的场景选择使用哪一种。在这篇博客中,我们将详细解析#{}和${}的区别和应用,并结合实际例子加深理解。

一、#{}与${}的基础介绍

1.1 #{}的使用

#{}是MyBatis中的占位符语法,表示参数值会被替换成SQL语句中的参数,同时它会将传入的参数进行预编译。MyBatis会自动为参数值做类型转换,并且防止SQL注入。具体来说,`#{}会通过PreparedStatement绑定参数,在SQL执行前对参数进行处理和转义,从而避免了SQL注入的问题。

示例:使用#{}进行参数传递
<select id="getUserByName" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username = #{username}
</select>

假设传入的username参数为zhangxiangwei,最终执行的SQL为:

SELECT * FROM users WHERE username = 'zhangxiangwei'

注意,`#{}会自动为字符串参数加上单引号,从而防止SQL注入。

1.2 ${}的使用

${}是MyBatis中的另一种占位符语法,它不会对参数进行预编译,而是直接将参数值拼接到SQL语句中。由于没有预编译,${}存在SQL注入的风险,因此使用时必须谨慎。

示例:使用${}进行参数传递
<select id="getUserByField" parameterType="String" resultType="User">
    SELECT ${fieldName} FROM users WHERE user_age = 22
</select>

如果传入的fieldName参数为user_name,那么最终执行的SQL为:

SELECT user_name FROM users WHERE user_age = 22

这里,user_name直接拼接到SQL语句中,而没有加上单引号,且没有进行任何类型转换。

二、#{}与${}的区别

2.1 安全性

  • #{}:使用#{}时,MyBatis会对传入的参数进行预编译,并自动转义参数内容,这样可以有效防止SQL注入攻击。
  • ${}:使用${}时,传入的参数会直接拼接到SQL中,无法进行参数值的转义或预编译,这就导致了SQL注入的风险。必须特别注意,如果使用${},你需要确保传入的参数是可信的。

2.2 适用场景

  • #{}:适用于传入具体的字段值、常规的查询条件等。大多数情况,尤其是涉及用户输入时,推荐使用#{}
  • ${}:通常用于动态拼接字段名、表名等不可预见的内容。当字段或表名需要动态变化时,使用${}可以实现动态拼接。

2.3 性能

  • #{}:使用`#{}时,MyBatis会生成预编译的SQL语句,能够提高性能,因为数据库可以缓存预编译语句并避免每次都解析SQL。
  • ${}:每次使用${}时,MyBatis都会生成新的SQL语句并直接发送给数据库执行,这可能会影响性能,尤其是在高并发环境下。

2.4 SQL注入风险

  • #{}:由于采用了预编译,#{}能够有效防止SQL注入。
  • ${}:由于直接拼接参数值,${}极易引发SQL注入攻击。如果不加防范措施,恶意用户可以通过构造特殊输入来修改SQL语句,进行非法操作。

三、实际应用中的选择

3.1 使用#{}防止SQL注入

场景:当需要传递查询条件值、ID、字符串等数据时,应优先使用`#{},如查询用户时传入用户名。

<select id="getUserByName" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username = #{username}
</select>

优点

  • 自动防止SQL注入
  • 支持类型转换和参数转义

3.2 使用${}进行动态SQL拼接

场景:当需要动态指定表名或字段名时,可以使用${}。例如,生成动态排序SQL时。

<select id="getUsersWithDynamicSorting" parameterType="map" resultType="User">
  SELECT * FROM users
  WHERE 1=1  <!-- 为了方便拼接,可以始终使用一个始终成立的条件 -->
 
  <if test="sortField != null and sortOrder != null">
    ORDER BY ${sortField} ${sortOrder}
  </if>
</select>

这里,sortFieldsortOrder是动态传入的值。使用${}来直接拼接排序字段和排序顺序,避免了#{}无法用于列名和排序字段的局限。

注意:在使用${}时,务必确保传入的字段或表名是可信的。如果sortField来自用户输入,可能会引发SQL注入风险。

3.3 使用#{}实现模糊查询

当使用#{}进行模糊查询时,可以结合LIKE语句来实现,避免SQL注入。

<select id="searchUser" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username LIKE CONCAT('%', #{username}, '%')
</select>

在这个例子中,#{}会安全地传递username参数,并将其包含在LIKE查询条件中。

四、总结

  1. #{} 是MyBatis中最常用的占位符,适用于大多数情况,能够防止SQL注入并提高SQL性能。
  2. ${} 适用于动态拼接表名、字段名等结构性内容,但要小心SQL注入风险。
  3. 在实际开发中,尽量使用#{},只在无法使用#{}的情况下(如动态列名、表名等)使用${}
  4. 动态SQL时,尤其是涉及排序等操作时,使用${}来拼接字段名和排序方式。

通过掌握#{}和${}的使用方式,可以在保证代码安全性的同时,灵活地进行动态SQL的拼接和查询。


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

相关文章:

  • Linux中的基本指令(二)
  • 深度探索DeepSeek-R1:AI大模型的本地应用与个人知识库构建
  • TCP编程
  • Android 使用ExpandableListView时,需要注意哪些细节
  • [paddle] 矩阵相关的指标
  • 自研有限元软件与ANSYS精度对比-Bar3D2Node三维杆单元模型-央视大裤衩实例
  • iOS文字滚动:使用CATextLayer实现的跑马灯(附源码)
  • 2. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务概述与演变
  • 整理:熟悉MySQL的使用和运行原理,掌握索引、事务、锁等机制。了解存储引擎、读写分离、分库分表。
  • QT笔记——多语言翻译
  • 传感器——针孔相机模型
  • java开发面试自我介绍模板_java面试自我介绍3篇
  • 8-登录流程
  • kakailio官网推荐的安装流程ubuntu 22.04
  • 解决php8.3无法加载curl扩展
  • 【Kubernetes Pod间通信-第2篇】使用BGP实现Pod到Pod的通信
  • 【R语言】数据操作
  • trinitycore服务器离线,原来是mysql里数据库flag设置为2离线状态了
  • 安卓系统源码如何导入原生androidx资源文件?
  • 说一下JVM管理的常见参数
  • 怀旧经典:1200+款红白机游戏合集,Windows版一键畅玩
  • 【LeetCode 刷题】贪心算法(2)-进阶
  • LLM框架对比选择:MaxKB、Dify、FastGPT、RagFlow【RAG+AI工作流+Agent]
  • uniapp商城之用户模块【会员中心】
  • 老游戏回顾:G2
  • openwebui入门