MyBatis中的$和#,用不好,准备走人!
作者:程序猿的内心独白
https://m.toutiaocdn.com/i6685496024770806280
这是一次代码优化过程中发现的问题,在功能优化后发现部分数据查不到出来了,问题就在于一条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<Integer>,这样问题就完美的解决了,既实现了我们的功能 ,又解决了安全性问题。
关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取一份栈长整理的 Java 最新技术干货。
最近干货分享
点击「阅读原文」加入栈长的战队~
MyBatis中的$和#,用不好,准备走人!的更多相关文章
- Mybatis中配置Mapper的方法
在这篇文章中我主要想讲一下Mybatis配置文件中mappers元素的配置.关于基础部分的内容可以参考http://haohaoxuexi.iteye.com/blog/1333271. 我们知道在M ...
- mybatis中模糊查询的使用以及一些细节问题的注意事项
页面有个功能 为 根据 品牌名进行 关键字查询,对应到数据库的是brand表的name字段的模糊查询 如果用的是SSM框架,在mybatis中我们需要自己写sql语句,涉及到like的模糊查询,myb ...
- 【MyBatis学习13】MyBatis中的二级缓存
1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加 ...
- MyBatis从入门到精通(十四):在MyBatis中使用类型处理器
最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解在MyBatis中如何 ...
- 从Mybatis中#和$的区别到SQL预编译
#和$的区别 Mybatis中参数传递可以通过#和$设置.它们的区别是什么呢? # Mybatis在解析SQL语句时,sql语句中的参数会被预编译为占位符问号? $ Mybatis在解析SQL语句时, ...
- mybatis中的#和$的区别 以及 防止sql注入
声明:这是转载的. mybatis中的#和$的区别 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sq ...
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- 记录一次bug解决过程:mybatis中$和#的使用
一.总结 mybatis中使用sqlMap进行sql查询时,经常需要动态传递参数.动态SQL是mybatis的强大特性之一,也是它优于其他ORM框架的一个重要原因.mybatis在对sql语句进行预编 ...
- mybatis中#{}与${}的差别(如何防止sql注入)
默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义. # ...
- mybatis 中的where标签
mybatis中的where标签可以去除 开头的 and 或者 or 但是放在后面的不行 失败的: <select id="countNotesByParam" parame ...
随机推荐
- bootstrap复习
菜单 <div class="row">下拉菜单/分裂菜单</div> <div class="dropdown btn-group&quo ...
- service worker介绍
原文:Service workers explained 译者:neal1991 welcome to star my articles-translator, providing you advan ...
- Centos7 配置rsyslog客户端接收远程日志
rsyslog 因为路由器我设定每天重启,但是日志一重启就会清除,并且路由器最多只能保存1024条记录,所以我想把路由器的日志记录到一台服务器上,发现路由器包含远程日志功能 于是我就在我的centos ...
- C#Stopwatch的简单计时 [收藏]
Stopwatch 类 命名空间:System.Diagnostics.Stopwatch 实例化:Stopwatch getTime=new Stopwatch(); 开始计时:getTime.St ...
- linux 配置 Sersync
[root@SERSYNC sersync]# cp conf/confxml.xml conf/confxml.xml.bak.$(date +%F) [root@SERSYNC sersync]# ...
- .net Console.ReadLine无效
代码中出现了 Console.ReadLine无效解决办法:把应用程序的输出类型改为 控制台应用程序
- sass @import 规则
@import 根据文件名引入. 默认情况下,它会寻找 Sass 文件并直接引入, 但是,在少数几种情况下,它会被编译成 CSS 的 @import 规则: 如果文件的扩展名是 .css. 如果文件名 ...
- window环境下mysql导入sql文件时报错:ERROR: ASCII '\0' appeared in the statement
错误信息: ERROR: ASCII '\0' appeared in the statement, but this is not allowed unless option --binary-mo ...
- 外媒:Apple面临着印度iPhone的停用
据外媒报道:印度电信管理局(TRAI)制定遏制令人讨厌的消息的新规则可能导致印度数百万部iPhone的停用. 该监管机构本周早些时候宣布了“2018年电信商业通信客户偏好规定”,根据该规定,它已提议“ ...
- JavaWeb(九):上传和下载
表单 进行文件上传时, 表单需要做的准备: 1). 请求方式为 POST: <form action="uploadServlet" method="post&qu ...