Mybatis使用order by排序使用#无法正确执行的解决之#与$的区别

本文探讨了在MyBatis中使用动态SQL时遇到的问题:通过#{variable}

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

今天遇到一个问题,mysql数据库使用mybatis在mapper.xml写动态sql  order by无法正确使用,没有报错,看日志也是传入了值

后来自己修改order by传入的值,发现对sql没有影响,说明这个sql没有正确执行

首先sql是这样写的

order by #{ORDER_BY}
		

外部定义是

private static final String ORDER_BY = "name ASC";

查看日志

 Parameters: name ASC(String), 0(Integer), 10(Integer)

看到ORDER_BY的确传进来了,就是这个name ASC(String),但是它是String类型的,这时sql语句为 order by "name ASC",

大家可以在mysql里面直接这样写写,sql语句会执行,但是没有作用,也不会报错

下面改成

order by ${ORDER_BY}
查看日志

Parameters: 0(Integer), 10(Integer)

没有了name ASC(String)   但是结果正确执行了


网上查找资料:

(1)对于形如#{variable} 的变量,Mybatis会将其视为字符串值,在变量替换成功后,缺省地给变量值加上引号。"variable"

 (2)对于形如${variable}的变量,Mybatis会将其视作直接变量,即在变量替换成功后,不会再给其加上引号。     variable

 所以在动态sql中,#{variable} 需要去掉 "",比如正常sql赋值一般是这样的and name= #{name},因为是=赋值,所以会获取内容,去掉""

${variable}可以直接使用,比如order by ${name}   传入的直接是name,不带双引号,可以直接使用,

并且order by不是 =赋值,所以如果直接order by #{name},结果是order by "name",自然无法执行了


总结#{variable} 传入字符串,可以在日志查看到传入的参数,需要赋值后使用,可以有效防止sql注入

${variable}是直接传入变量,在日志查看不到传入的变量,直接在sql中执行,无法防止sql注入

所以,尽量用#{variable}格式,如果不是类似=赋值后再使用的sql,需要使用${variable}


网上还说有<![CDATA[]]>内需要注意#与$的区别,暂时没遇到,先备注一下。




<think>好的,用户想了解MyBatis#$区别及用法。我之前学过的相关知识需要回顾一下。首先,记得#是预编译处理,$是字符串替换。不过具体细节可能需要再确认。 根据引用内容,比如引用[1]提到#$是参数占位符,处理机制不同。引用[4]详细说明#{}可以防止SQL注入,使用PreparedStatement的set方法,而$是直接替换,可能有注入风险。用户可能需要知道两者的核心区别,包括安全性、处理方式和使用场景。 我应该先分点说明两者的差异,比如处理机制、安全性、性能和应用场景。同时需要举例说明,这样更清晰。比如,用#的时候,参数会被预编译为?,而$直接替换成字符串。例如,在order by的场景下,可能需要用$,但要注意风险。 还要注意用户可能在实际使用中遇到的问题,比如什么时候必须用$,虽然不安全但必要的情况。同时,要强调预防SQL注入的重要性,推荐优先使用#。可能需要给出代码示例,比如在XML中的SQL写法差异。 另外,引用[3]提到了MyBatis执行入口,可能涉及底层原理,比如#会生成PreparedStatement,而$生成Statement。这点对理解区别有帮助,可以简单提及。 最后,生成相关问题时要覆盖原理、应用场景、安全措施和替换情况。用户可能需要进一步了解如何避免$的风险,或者动态SQL的其他方法,比如使用OGNL表达式或其他MyBatis标签。 需要确保回答结构清晰,先总述区别,再分点详细说明,每个点都结合例子,最后总结使用建议。同时检查LaTeX格式是否正确,比如变量用$包裹,但系统级指令要求行内数学表达式用$...$,这里可能不需要,但要注意用户的问题中是否有数学内容,这里没有,所以可能不需要处理。不过代码块要用正确的格式,比如SQL示例和Java代码。 现在整理回答,确保每个部分符合用户的要求,引用正确,并且在适当的位置添加引用标记。例如,在提到预编译处理时引用[4],在提到执行入口时引用[3]。</think>### MyBatis#$区别及用法解析 #### 一、核心区别 1. **处理机制** - **`#{}`**:基于预编译的占位符,参数会被替换为`?`,并通过`PreparedStatement`的`setXXX()`方法赋值,生成安全的SQL语句[^4]。 - **`${}`**:基于字符串替换,直接将参数值拼接为SQL语句,可能引发SQL注入风险[^2]。 2. **安全性** - **`#{}`**:自动转义特殊字符(如单引号),防止SQL注入。 - **`${}`**:直接拼接原始值,若参数来自用户输入,需手动过滤危险字符。 3. **性能** - **`#{}`**:预编译的SQL可被数据库缓存,提升重复执行效率[^4]。 - **`${}`**:每次生成新SQL,无缓存优势。 --- #### 二、使用场景对比 | 场景 | `#{}`适用性 | `${}`适用性 | 示例 | |--------------------|-------------|-------------|--------------------------------------------------------------| | **普通参数传递** | ✅ | ❌ | `SELECT * FROM users WHERE id = #{userId}` | | **动态表名/列名** | ❌ | ✅ | `SELECT ${column} FROM ${tableName}` | | **ORDER BY排序** | ❌ | ✅ | `SELECT * FROM products ORDER BY ${sortField} ${sortOrder}` | | **LIKE模糊查询** | ✅(需拼接) | ❌ | `WHERE name LIKE CONCAT(&#39;%&#39;, #{keyword}, &#39;%&#39;)` | --- #### 三、底层原理 - **`#{}`**:通过`ParameterHandler`处理参数,生成`PreparedStatement`,执行时替换占位符[^3]。 - **`${}`**:在SQL解析阶段直接替换为字符串,生成`Statement`对象[^3]。 --- #### 四、代码示例 ```xml <!-- 安全用法:使用#{}传递参数 --> <select id="getUserById" resultType="User"> SELECT * FROM users WHERE id = #{userId} </select> <!-- 风险用法:使用${}动态拼接列名 --> <select id="getDynamicColumn" resultType="map"> SELECT ${columnName} FROM products </select> ``` --- #### 五、使用建议 1. **优先使用`#{}`**:确保安全性和性能。 2. **谨慎使用`${}`**:仅在动态表名、列名或SQL关键字无法用`#{}`实现时使用,且需手动校验参数来源。 3. **防注入措施**:若必须用`${}`,可通过白名单校验参数内容(如固定枚举值)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值