Mybatis 中 $ 和 #千万不要乱用

  • Post author:
  • Post category:其他




开头

这是一次代码优化过程中发现的问题,在功能优化后发现部分数据查不到出来了,问题就在于一条 sql 上的 #和 $。

下图为两条 sql:

从图上可以看出 wwlr.LabelId in(${showLabels}) 和 wwlr.LabelId in(#{showLabels}),其中 showLabels 是传进来一个字符串类型的参数,参数的样子是这样的 “4,44,514”,问题就出在这个参数传进来后 #和 $ 处理的方式是不一样的。

区别

1、#{} 是预编译处理,MyBatis 在处理 #{} 时,它会将 sql 中的 #{ } 替换为?,然后调用 PreparedStatement 的 set 方法来赋值,传入字符串后,会在值两边加上单引号,如上面的值 “4,44,514” 就会变成 “ ‘4,44,514’ ”;

2、${} 是字符串替换, MyBatis 在处理 ${} 时, 它会将 sql 中的 ${ } 替换为变量的值,传入的数据不会加两边加上单引号。

注意:使用 ${ } 会导致 sql 注入,不利于系统的安全性!

SQL 注入:就是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令。常见的有匿名登录(在登录框输入恶意的字符串)、借助异常获取数据库信息等


应用场合:

1、#{}:主要用户获取 DAO 中的参数数据, 在映射文件的 SQL 语句中出现 #{} 表达式, 底层会创建预编译的 SQL;

2、${}: 主要用于获取配置文件数据, DAO 接口中的参数信息, 当 $ 出现在映射文件的 SQL 语句中时创建的不是预编译的 SQL, 而是字符串的拼接, 有可能会导致 SQL 注入问题. 所以一般使用 $ 接收 dao 参数时, 这些参数一般是字段名, 表名等, 例如 order by {column}。

注:

${} 获取 DAO 参数数据时, 参数必须使用 @param 注解进行修饰或者使用下标或者参数 #{param1} 形式;

#{} 获取 DAO 参数数据时, 假如参数个数多于一个可有选择的使用 @param。

问题分析

其实刚开始我也没太去看 sql 里的 #和 $,我把 sql 放到数据库跑一切正常,所以我就将代码的执行 sql 输出到控制台了,具体是这么一个输出 sql 的配置文件:

输出后,终于发现了问题在哪里。。。。

看了上面的区别介绍,相信大家其实都应该知道区别在哪里,我们的问题在哪里,其实就是 sql 在 in 的时候 ,里面的数据被加了两个双引号。“wwlr.LabelId in(4,44,514)就会变成 wwlr.LabelId in(‘4,44,514’ );所以导致部分数据查不到了。

解决办法


1、快速解决

最快的方法就是把 #直接替换成 $,这样问题应该就可以解决了。

但是,我很无语,我确没有解决。

本地跑代码一点问题都没有,部署到公司的 docker 上问题一样没解决,给人的感觉就是代码根本没有从 #变 $。

大家都知道 $ 其实是有危险性,会容易被 sql 注入,具我所知道,我们公司的 docker 是会加一层防止 sql 注入的功能 ,所以不知道是不是这个功能把的 $ 无效掉了。

当然,我也没有去再到服务上打出 sql 来看一下,因为本来 $ 就是不太安全的,所以我换了一种方式处理。


2、foreach 标签的使用

foreach 标签主要用于构建 in 条件,他可以在 sql 中对集合进行迭代。

先来看看语法:

通过上图,大家也应该也了解和使用这个标签了吧。

那对于我们项目中的改造,其实就是把原来传进来的字符型参数变成 List,这样问题就完美的解决了,既实现了我们的功能 ,又解决了安全性问题。


原文链接:

https://m.toutiaocdn.com/i6685496024770806280