• 已删除用户
Administrator
发布于 2023-09-18 / 5 阅读
0

MyBatis中#与$的区别(进阶版)

在面试时遇到“MyBatis中#与$的区别”这个问题的时候,99%的人首先想到的一定是${xxx}不会对参数进行预编译,存在SQL注入风险。在昨晚的一个版本发不上踩了“${xxx}”的坑,排查了近 6 个小时。

背景

昨晚的版本发布中,一个查询接口在测试环境运行良好,发布到生产环境后查询耗时 10 秒以上。

a. 语句直接在客户端上执行,耗时在 0.00X 秒左右。排除了 SQL 语句问题和数据量问题。 2. 该项目跨云部署,怀疑为网络问题。测试其他接口正常,排除了网络问题。

b. 经过无数次的反复排查,发现了一段 Github Copilot 代码补全的 SQL, 条件中使用了${xxx},报着先消灭安全问题的想法,更新发布了一版,发现查询缓慢问题也顺带解决了。

#与$的区别

  1. SQL 注入风险
    ${xxx}占位符将查询参数直接拼接到 SQL 语句中,而不会进行预编译。这样做存在安全风险,如果不正确处理输入的参数,可能会导致 SQL 注入攻击。为了防止 SQL 注入,MyBatis 推荐使用#{xxx}占位符,它会对参数进行预编译并进行安全转义。

  2. SQL 解析和优化
    由于${xxx}占位符嵌入参数值后形成的 SQL 语句是动态拼接的,数据库在执行这类语句时无法提前进行解析和优化。这可能导致数据库无法充分利用索引、执行计划等优化策略,从而影响查询性能。

  3. 缓存失效
    ${xxx}占位符会将参数值作为字符串直接嵌入到 SQL 语句中,这会导致每个不同的参数值都生成一个新的 SQL 语句。这种方式可能导致缓存失效,因为每个 SQL 语句都被认为是不同的查询,无法复用缓存结果。相比之下,#{xxx}占位符会将参数值作为参数传递给预编译语句,从而保持 SQL 语句的一致性,使得缓存可以更有效地工作。

结论

为了提高性能和安全性,建议尽量使用#{xxx}占位符替代${xxx}占位符。如果确实需要使用${xxx}占位符,务必注意参数的安全性,并进行必要的输入校验和转义处理,以防止 SQL 注入攻击。