mybatis的#{}和${}的区别以及order by注入问题

本文解析了在使用MyBatis进行数据库操作时,前端传来的排序字段和方式未生效的问题。通过对比#{}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题

根据前端传过来的表格排序字段和排序方式,后端使用的mybaits

select XXXX from table order by #{column} #{desc}

如上面的形式发现排序没有生效,查看打印的日志发现实际执行的sql为,排序没有生效

select XXXXX from table order by "column" "desc"
二、原因分析

主要还是对mybatis传参形式不了解,官方介绍如下:

By default, using the #{} syntax will cause MyBatis to generate PreparedStatement properties and set the values safely against the PreparedStatement parameters (e.g. ?). While this is safer, faster and almost always preferred, sometimes you just want to directly inject an unmodified string into the SQL Statement. For example, for ORDER BY, you might use something like this:
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

从官方文档中可以看出#{}相当于jdbc中的preparedstatement,进行了预编译,而${}直接是字符串本身,是有意设计成这样,方便拼接成动态sql,但是这样也带来缺点,可能存在注入问题。

参考阅读:http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Parameters

转载于:https://www.cnblogs.com/xieshuang/p/11017121.html

<think>我们正在讨论MyBatis#{}${}的区别使用场景。根据引用[1]、[2]、[3]、[4]、[5]的内容,可以总结如下:#{}${}都是MyBatis中用于动态传递参数的符号,但它们的工作机制安全性有本质区别:1.**处理机制不同**:-`#{}`:MyBatis会将SQL中的`#{}`替换为预编译语句中的占位符`?`,然后使用PreparedStatement的参数绑定机制来安全地设置值。这种方式会对传入的参数进行类型处理(如字符串类型会自动加单引号)并转义特殊字符,有效防止SQL注入攻击。-`${}`:MyBatis会直接将`${}`中的内容替换为参数的字符串值(不进行预编译处理)。如果参数是字符串类型,不会自动添加引号,所以需要手动添加单引号。这种方式是简单的字符串替换,存在SQL注入风险。2.**安全性差异**:-使用`#{}`时,由于参数会被预编译,因此可以防止SQL注入。例如,当传入参数为`a&#39;or&#39;1&#39;=&#39;1`时,使用`#{}`会转义单引号,变成`\&#39;`,从而避免非法查询。-使用`${}`时,如果参数值包含恶意SQL片段,会被直接拼接到SQL语句中执行,导致SQL注入风险。3.**适用场景**:-`#{}`适用于绝大多数场景,特别是作为查询条件值(WHERE子句中的值)、INSERT/UPDATE语句中的字段值等需要参数绑定的地方。-`${}`通常用于需要动态指定SQL语句非值部分的情况,例如:-动态排序字段(ORDERBY子句),如:`ORDERBY${columnName}[ASC|DESC]`(引用[1]、[2]、[4])-动态指定表名或列名(非值部分),如:`SELECT*FROM${tableName}`(引用[4])-动态SQL片段(如动态指定GROUPBY字段)4.**性能考虑**:-`#{}`生成的预编译语句可以被数据库缓存重用,提高执行效率。-`${}`每次都会生成新的SQL语句(因为内容可能变化),无法利用预编译缓存,性能略低。5.**使用细节**:-在`${}`中引用字符串类型参数时,需要在XML中手动添加单引号(如`&#39;${name}&#39;`),但这样仍然不安全(引用[5])。建议对用户输入进行严格过滤或避免使用。-在编写LIKE模糊查询时,推荐用`#{}`配合通配符处理(如`LIKECONCAT(&#39;%&#39;,#{keyword},&#39;%&#39;)`或代码中添加`%`),而不是用`${}`(引用[4])。###代码示例对比####安全用法(使用`#{}`)```xml<selectid="selectUser"resultType="User">SELECT*FROMusersWHEREname=#{name}ANDage=#{age}</select>```####动态排序(必须使用`${}`)```xml<selectid="selectUsersOrdered"resultType="User">SELECT*FROMusersORDERBY${orderColumn}${orderDirection}</select>```>⚠️注意:使用`${}`时,应确保参数值来自可信源(如后端枚举值),或进行严格校验。###总结|特性|`#{}`|`${}`||--------------|-------|------------||工作机制|预编译占位符|字符串替换||安全性|高(防注入)|低(有注入风险)||自动添加引号|是|否(需手动)||适用场景|参数值|动态SQL片段(表名/列名/排序)|因此,**在多数情况下优先使用`#{}`;仅当需要动态生成SQL关键字或标识符时(无法用预编译占位符代替),才谨慎使用`${}`**。§§相关问题§§1.如何安全地使用MyBatis动态表名?2.MyBatis中如何预防SQL注入?3.除了#{}${},MyBatis还有哪些动态SQL标签?</think> ### MyBatis中`#{}``${}`的区别使用场景 #### 一、核心区别 | **特性** | **`#{}`** | **`${}`** | |----------------|-------------------------------------|-------------------------------------| | **处理机制** | 预编译占位符 (`?`) | 字符串直接替换 | | **安全性** | 防止SQL注入(自动转义特殊字符)[^4] | 有SQL注入风险(原样拼接)[^3][^4] | | **引号处理** | 自动添加引号(如字符串类型) | 需手动添加引号(如`&#39;${value}&#39;`) | | **性能** | 预编译语句可复用 | 每次生成新SQL | #### 二、使用场景对比 1. **`#{}` 的适用场景** - **条件值传递**(WHERE子句): ```xml SELECT * FROM user WHERE name = #{name} ``` 编译后:`SELECT * FROM user WHERE name = ?`(安全)[^2][^3] - **LIKE模糊查询**(需配合通配符): ```xml SELECT * FROM user WHERE name LIKE CONCAT(&#39;%&#39;, #{keyword}, &#39;%&#39;) ``` - **INSERT/UPDATE操作**: ```xml INSERT INTO user (name, age) VALUES (#{name}, #{age}) ``` 2. **`${}` 的适用场景** - **动态排序字段**(ORDER BY): ```xml SELECT * FROM user ORDER BY ${orderField} ASC ``` *若用`#{}`会生成`ORDER BY &#39;name&#39;`(语法错误)* [^1][^4] - **动态表名/列名**: ```xml SELECT * FROM ${tableName} ``` - **固定SQL片段**: ```xml ${"LIMIT 10"} <!-- 直接拼接SQL关键字 --> ``` #### 三、安全性对比(SQL注入示例) ```xml <!-- 危险!传入 `name = "a&#39; OR &#39;1&#39;=&#39;1"` 会导致全部数据泄露 --> SELECT * FROM user WHERE name = &#39;${name}&#39; <!-- 安全!参数会被转义为: `a\&#39; OR \&#39;1\&#39;=\&#39;1` --> SELECT * FROM user WHERE name = #{name} ``` > 💡 **结论**:`${}`需要**严格校验输入**(如只允许枚举值),否则应避免使用[^4][^5]。 #### 四、性能影响 - `#{}` 生成的预编译语句可被**数据库缓存重用**,尤其在高并发时性能更优[^3] - `${}` 每次生成**全新SQL语句**,增加数据库解析开销 ### 最佳实践总结 1. **默认优先使用`#{}`**:适用于>95%的场景(值传递) 2. **谨慎使用`${}`**:仅用于**动态表名/列名、排序字段**等非值场景[^1][^4] 3. **防御措施**: - 对`${}`参数做**白名单校验**(如只允许特定字段名) - 避免直接拼接用户输入(如`ORDER BY ${userInput}`) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值