【实力踩坑】ORDER BY 不生效

博客记录了组内自定义动态表头排序时,SQL中order by字段不生效的问题。经讨论发现,MyBatis里#{}用于预处理,${}用于直接替换,排序时ORDER BY filed只能用${},#{}会使解析出错。最后换成${}查询生效,还提醒遇到问题可找人讨论。

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

很简单的一个问题但还是值得记录一下。

组内自定义了动态表头,支持表头字段的排序(表头字段列名是什么,排序查询传进来的就是什么),那列表查询的时候只好把 sql 写成一个嵌套子查询,在最后进行动态 order by orderFiled 的形式,代码如下:

select *
    from (
           select t1.c1 as column1, t1.c2 as column2, t2.c3 as column3
           from demo_table t1
                  inner join demo_table t2 on t1.c1 = t2.c1
         ) t
    order by #{orderField} #{orderType}

orderField 的值如下:

  • column1
  • column2
  • column3

orderType 的值如下:

  • asc
  • desc

然后我就天真的传入字段进行排序了,因为 DEBUG 日志级别,控制台打印 SQL 日志如下:

==>  Preparing: select * from ( select t1.c1 as column1, t1.c2 as column2, t2.c3 as column3 from demo_table t1 inner join demo_table t2 on t1.c1 = t2.c1 ) t order by ? ? 
==> Parameters: column1(String), asc(String)

看着没毛病哈,但是实际查询 order by 后面的字段就是不生效,我尝试了好几种方式就 TM 不生效,我很气啊,就这个小破玩意耽误了我好长时间,咋整呢?

最后和小伙伴回去讨论,一语点醒梦中人,妈的是#{}的坑,还记得它的孪生兄弟${}不,先看下它俩的区别:

在MyBatis中,#{}和${}都是用来替换参数的,但它们的功能和用途存在一些差异。

  • #{}用于预处理,而KaTeX parse error: Expected 'EOF', got '#' at position 14: {}用于直接替换。这意味着#̲{}解析为JDBC预编译语句(…{}则仅仅是一个纯粹的字符串替换。

  • 在解析阶段,#{}会将String类型的数据自动加上引号,而其他数据类型不会;而${}解析之后是什么就是什么,不会当做字符串处理。

  • 从安全性角度看,使用#{}不存在安全问题,而使用存在安全问题。因为{}在动态SQL解析阶段会进行变量替换,可能会被注入恶意代码。

  • 在某些特殊场合下,如使用排序时ORDER BY filed,只能使用{},不能用#{}。这是因为#{}在解析之后会将String类型的数据自动加上引号,导致解析错误。

  • 综上所述,#{}和${}在功能、使用场景和安全性方面存在差异。在实际使用中,需要根据具体需求和场景选择合适的参数替换方式。

从这里应该能发现了吧,#{}是个占位符的形式,会把参数默认解析为一个字符串常量,而order by '字符串常量'是没有任何效果的,从而判定出就是它的坑,而使用${}会把字段值完全拼接在 SQL 中,也就是是啥就是啥,当然这种方式会有注入的风险,但是对此处的实际场景来说也没啥风险,果断换成${}再次查询生效了。

外日他 dei,就这个破玩意浪费了我好长时间,虽然很简单,但是第一次踩到,记录一下。

启发: 以后遇到解决不了的问题,不要死磕,找小伙伴一起讨论下,说不定哪句话就直接点醒你。

谨以此记录我这不健全的脑干,只好一步一个坑来的实在。

当 `MySQL` 中的 `ORDER BY` 子句不生效时,可能是由以下几个原因导致的: ### 常见的原因及解决办法 1. **查询结果被缓存** 如果数据已经被缓存,并且排序没有强制应用到最终的结果集上,则可能会忽略 `ORDER BY` 操作。尝试添加 `SQL_NO_CACHE` 来避免这种情况: ```sql SELECT * FROM table_name SQL_NO_CACHE ORDER BY column_name ASC; ``` 2. **字段值存在 NULL** 当需要按某个列进行排序而该列包含大量空值 (`NULL`) 时,默认情况下 MySQL 可能将所有 `NULL` 放置在最前或最后(取决于顺序)。可以明确指定如何处理这些情况: ```sql -- 将 NULL 置于末尾 (ASC) SELECT * FROM table_name ORDER BY IF(column_name IS NULL, 1, 0), column_name ASC; -- 或者 DESC 排序类似调整 ``` 3. **分页与 LIMIT 的干扰** 使用了 `LIMIT` 进行分页操作时如果忘记加上对应的排序规则也可能出现问题;例如只写了部分语句如下的错误示例不会按照预期工作: ```sql SELECT ... WHERE condition LIMIT offset, rows; // 缺少 ORDER BY 部分会随机返回记录。 ``` 4. **索引覆盖限制** 若表上有合适的复合索引来支持直接访问满足条件的数据块,但未显式指出排序依据点位则可能导致优化器跳过实际排布步骤。 5. **拼接字符串或其他函数调用影响正常解析路径** 对某些复杂的表达式比如计算字段、时间戳转换等做二次加工后作为目标键值传入order by里头的话容易引发混乱状态。 6. **大小写敏感度配置问题** 字符串类型的比较受到字符编码设定的影响,在不同的数据库实例间同步迁移代码文件或者切换系统环境变量设置不当均会引起差异反应。 --- #### 解决建议总结: - 检查是否遗漏书写完整的 `ORDER BY` 子段名及其升降次序; - 明确对特殊状况像 `nulls first|last` 的额外声明需求; - 结合实际业务场景考虑是否有必要针对特定运算后的数值再重新规划优先级逻辑; - 查看当前服务器版本特性以及默认选项是否存在偏差从而引起异常现象发生;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Commit日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值