Mybaits中Like 的使用方式以及一些注意点
做一个积极的人
编码、改bug、提升自己
我有一个乐园,面向编程,春暖花开!
模糊查询在项目中还是经常使用的,本文就简单整理Mybatis中使用Like进行模糊查询的几种写法以及一些常见的问题。
使用Springboot简单配置一下Mybatis,然后进行说明。Springboot集成Mybatis这里就不做介绍了。
初始数据
方式一
在Mybatis中的第一种写法:
<!--有sql注入问题-->
<select id="findUserByLikeName1" parameterType="java.lang.String" resultMap="user">
select * from t_user where name like '%${name}%'
</select>
这种会有sql注入的问题,需要明白在 Mybatis中 $
和 #
使用的区别。这种写法也不能加jdbcType=VARCHAR
,否则也会报错。
做了个简单的测试:
@Test
public void findUserByLikeName1(){
List<User> test = userMapper.findUserByLikeName1("Cloud");
//select * from t_user where name like '%Cloud%'
System.out.println(test.size());// 查出一条
List<User> test1 = userMapper.findUserByLikeName1("' or '1=1");
//select * from t_user where name like '%' or '1=1%'
// 分析: '1=1%' 成立
System.out.println(test1.size());// 查出了全部数据
}
注意:排序的字段也容易出现这个问题,在使用的时候也一定要注意。
order by ${orderBy}
第一种方式在实际开发过程中千万要注意,不要写成这样了。
方式二
在Mybatis中的第二种写法:
<!--直接在代码中拼接%, 不存在sql注入-->
<select id="findUserByLikeName2" parameterType="java.lang.String" resultMap="user">
select * from t_user where name like #{name,jdbcType=VARCHAR}
</select>
在代码中加上%
。
@Test
public void findUserByLikeName2(){
String name = "Cloud";
List<User> test = userMapper.findUserByLikeName2("%" +name+"%");
// select * from t_user where name like ?
// %Cloud%(String)
System.out.println(test.size());
}
这种方式在一些项目中也会看到。如果没有使用如Mybatis等ORM框架,直接写sql查询就这样拼接了。
方式三
在Mybatis中的第三种写法:
<!--concat Mysql和 Oracle区别 ,不存在sql注入-->
<select id="findUserByLikeName3" parameterType="java.lang.String" resultMap="user">
select * from t_user where name like concat('%',#{name,jdbcType=VARCHAR},'%')
</select>
测试:
@Test
public void findUserByLikeName3(){
String name = "Cloud";
List<User> test = userMapper.findUserByLikeName3(name);
// select * from t_user where name like concat('%',?,'%')
// Cloud(String)
System.out.println(test.size());
}
在实际开发中推荐使用这种方式。
小注意
当使用方式三的时候,如果查询的关键字就是%
,那情况会是什么? 初始化数据中name
有9条数据中包含%
。
查询的sql如下:
select * from t_user where name like concat('%','%','%')
查出来全部的数据,并不是只包含了%
的数据,如果查询_
也是一样的。
那这种情况肯定是不满足查询需求的,则需要调整。
①在代码中进行转义
@Test
public void findUserByLikeName3(){
String name = "%";
name = name.replaceAll("_", "\\\\_");
name = name.replaceAll("%", "\\\\%");
List<User> test = userMapper.findUserByLikeName3(name);
System.out.println(test.size());
}
②使用ESCAPE
<select id="findUserByLikeName4" parameterType="java.lang.String" resultMap="user">
select * from t_user where name like concat('%',#{name,jdbcType=VARCHAR},'%') ESCAPE '/'
</select>
测试:
@Test
public void findUserByLikeName4(){
// replaceAll("%", "/%").replaceAll("_", "/_")
String name = "%";
List<User> test = userMapper.findUserByLikeName4(name);
System.out.println(test.size());// 查到全部
List<User> test1 = userMapper.findUserByLikeName4("/" +name);
System.out.println(test1.size());//查到匹配%的记录
}
这两种本质都是对查询的关键字进行了处理,这种处理在代码中可以使用拦截器或者AOP等技术统一处理。
小总结
1、不要写方式1的这种模糊查询,容易发生sql注入!
建议使用第三种方式进行模糊查询
2、上面这三种模糊查询,都是使用%关键字%
,这种方式是不会走索引的,大数据量时候有查询效率问题
看情况,可以使用全文索引;或者使用ES进行
说明:网上有一些优化like的查询的,但是亲测后没啥用
3、注意关键词中有%、_这些特殊字符如何处理。
1、业务上不允许输入这些字符,直接过滤(前台、后台过滤)
2、使用上面的ESCAPE或者转义
备注: 由于本人能力有限,文中若有错误之处,欢迎指正。
原文地址:https://www.cnblogs.com/aflyun/p/11703659.html
- WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化
- WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇]
- 成为更好程序员的8种途径
- 探秘Tomcat——启动篇
- ai量化系统架构的思考
- 探秘Tomcat——连接器和容器的优雅启动
- 谈谈分布式事务之三: System.Transactions事务详解[上篇]
- WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(上篇)
- 谈谈分布式事务之二:基于DTC的分布式事务管理模型[下篇]
- 孙明俊:人工智能之算力演进
- 探秘Tomcat——一个简易的Servlet容器
- 2017年与机器学习相关的10大Python开源库
- 控制并发访问的三道屏障: WCF限流(Throttling)体系探秘[上篇]
- 探秘Tomcat——从一个简陋的Web服务器开始
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- codeforces1385D (递归+分治)
- codeforces1294D(思维+暴力)
- codeforces 1367D(思维)
- 数据库事务处理与资源池
- codeforces 1328D(思维)
- codeforces 1283D(BFS)
- codeforces 1213D2(贪心+思维)
- codeforces 1426E(贪心)
- codeforces 1374E1(贪心+优先队列)
- codeforces 455A(dp)
- codeforces 1296E1(贪心+思维)
- codeforces 1216E1(数学+暴力)
- JDBC基础入门使用
- codeforces 1353E(dp)
- codeforces 1396A(构造)