这是一次代码优化过程中发现的问题,在功能优化后发现部分数据查不到出来了,问题就在于一条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>,这样问题就完美的解决了,既实现了我们的功能 ,又解决了安全性问题。
到此这篇关于MyBatis中$和#深入讲解的文章就介绍到这了,更多相关MyBatis中$和#内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!
本文向大家介绍深入理解Mybatis中的resultType和resultMap,包括了深入理解Mybatis中的resultType和resultMap的使用技巧和注意事项,需要的朋友参考一下 一、概述 MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则是对外部Res
本文向大家介绍Spring中@Autowire注入的深入讲解,包括了Spring中@Autowire注入的深入讲解的使用技巧和注意事项,需要的朋友参考一下 一直在思考spring的@Autowire注入属性时到底是按类型注入还是按名称注入,今天写了一个测试来证明一下。 定义接口TestService 定义接口实现:TestServiceImpl1和TestServiceImpl2 定义一个bean
本文向大家介绍Tomcat中的Session与Cookie深入讲解,包括了Tomcat中的Session与Cookie深入讲解的使用技巧和注意事项,需要的朋友参考一下 前言 HTTP 是一种无状态通信协议,每个请求之间相互独立,服务器不能识别曾经来过的请求。而对于 Web 应用,它的活动都是依赖某个状态的,比如用户登录,此时使用 HTTP 就需要它在一次登录请求后,有为后续请求提供已登录信息的能力
本文向大家介绍深入讲解iOS开发中的UIViewController,包括了深入讲解iOS开发中的UIViewController的使用技巧和注意事项,需要的朋友参考一下 UIViewController顾名思义:视图控制器。应该在MVC设计模式中扮演控制层的角色。一些初学者在最开始的时候一直不理解为何有了UIView还要UIViewController做什么用,不都是向视图中增加view。在此我
本文向大家介绍Shell中重定向的深入讲解,包括了Shell中重定向的深入讲解的使用技巧和注意事项,需要的朋友参考一下 标准输入、标准输出和标准错误 一个程序的的输入可以来自于键盘,也可以来自于文件或者其他设备;同样的,一个程序也可以将输出显示在屏幕或者保存到文件中。这就涉及到标准输入、标准输出和标准错误。 程序的输入是标准输入,默认是键盘,用户可以将其指定为文件或其他设备。 程序的输出有两种,即
本文向大家介绍js中Generator函数的深入讲解,包括了js中Generator函数的深入讲解的使用技巧和注意事项,需要的朋友参考一下 前言 Generator函数是es6提供的一种异步编程的解决方案,语法行为与传统函数完全不一样。 Generator函数有多种理解角度,从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。 执 行Generator函数会返回一