MySQL WHERE 条件查询,重点搞懂 % 通配符,MySQL 会如何处理连续的 % 通配符
作者:沉默王二
发布时间:2024-02-25T10:10:07.227+0800
今天的内容大家一定要掌握,尤其是 MyBatis 中 #和$的区别,以及 MySQL 会如何处理连续的%通配符。
在**上一篇 **中,我们学习了简单的 SELECT 查询,但没有带上查询条件。要知道,真实的业务场景中,数量会非常大,有些甚至会有几百万、几千万条数据,如果不带上查询条件,一次性把全部数据查出来是不太现实的。
所以,我们通常要求在执行 SELECT 查询时,都要带上查询条件。那这一节,我们就来学习一些简单的 WHERE 条件查询。
我们仍然以**技术派 **的文章表 article 为例,比如说我们要查找标题为“聊聊分库分表”的文章,可以这么写:
SELECT * FROM article WHERE title = '聊聊分库分表';
这其中的 WHERE title = '聊聊分库分表' 就是查询条件,title 是字段名,'聊聊分库分表' 是字段值。
比较查询操作符
除了上面提到的 = 操作符,MySQL 还提供了很多其他的比较查询操作符,常用的有以下几种:
比如说,我们要查找 user_id 大于 1000 的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id > 1000;
其他的我就不一一展示了,很简单,大家可以自己试试(也没必要 😂,知道有这么一些比较操作符就行了,用到的时候会用就 OK)
区间查询
假如说我们要查询 user_id 在 1000 到 2000 之间的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id >= 1000 AND user_id
如果 searchParams.title 不为空,就会拼接 % 通配符,实现模糊查询。
其中的 concat 方法是 MySQL 的字符串拼接函数。
是 MyBatis 中参数占位符的标记,用于预处理语句(PreparedStatement)中,以防止 SQL 注入攻击。当使用#{}来包裹一个参数时,MyBatis 会在执行 SQL 之前将该参数的值安全地填充到 SQL 语句中。
注意,这是一个考点。在面试中,可能会被问到 # 和 $ 的区别。
$ 也是 MyBatis 中参数占位符的标记,用于直接拼接 SQL 语句,不会进行预处理。当使用${}来包裹一个参数时,MyBatis 会直接将该参数的值拼接到 SQL 语句中。
#{} 和 ${} 的区别在于,#{} 是预处理,会对参数进行安全处理,而 ${} 是直接拼接,不会对参数进行处理。
MyBatis 中的 # 和 $
我们这里稍微拓展一丢丢,假如 mapper.xml 文件中的 SQL 语句是这样的:
select * from user where name = #{name};
那么它将被解析为:
select * from user where name = ?;
一个 #{} 会被解析为一个参数占位符 ?。
而如果 xml 中的 SQL 语句是这样的:
select * from user where name = '${name}';
当我们传入的参数是 name = "王二" 时,它将被解析为:
select * from user where name = '王二';
$ 会直接拼接参数的值,不会进行预处理。这就存在 SQL 注入的风险。
假如有这样的 SQL 语句:
select * from ${tableName} where name = #{name}
当 tableName 为 user; delete user; -- 时,它将被解析为:
select * from user; delete user; -- where name = ?;
-- 是 SQL 中的注释符,表示注释掉后面的内容。于是,一条本来是 SQL 查询的语句,变成了删除 user 表的语句。
这是万万不能够的,当然了,这里讲的很浅,我们单独留一个传送门(里面再细讲):
连续的%通配符
我们这里来实验一下,假如查询条件中包含 % 通配符,MyBatis 会如何解析呢?MySQL 的执行结果又会怎么样呢?
我们还是以**技术派实战项目 **为例,假如我们要查询标题中包含“%0”的文章。
MyBatis
先来看 MyBatis 生成的 SQL 语句:
我把关键的部分摘出来:
Preparing: select a.id from article a where a.title like concat('%', ?, '%') order by a.update_time desc limit ?, ?
Parameters: %0(String), 0(Long), 10(Long)
可以看到,#{}是通过占位符 ? 的方式进行拼接的。
MySQL
那最终 MySQL 执行的 SQL 语句又是什么样的?
我们可以通过打开 MySQL 的通用查询日志(General Query Log)来辅助我们完成这项工作。
- 可以通过 SHOW VARIABLES LIKE 'general_log'; 来查看通用查询日志是否开启。ON 为开启,OFF 为关闭。
- 可以通过 SHOW VARIABLES LIKE 'general_log_file'; 来查看通用查询日志的文件路径。
如果未开启的话,可以通过 SET GLOBAL general_log = 'ON'; 来开启通用查询日志。
然后执行上面的查询,就可以在通用查询日志中看到 MySQL 执行的 SQL 语句。
可以通过文本工具打开日志文件,拉到最后,就可以找到对应的 SQL 语句。我的是 macOS,所以直接用 vim 就可以打开。
可以看到,最终 MySQL 执行的 SQL 语句是这样的(省略部分 SQL 内容):
select a.id from article a where a.title like concat('%', '%0', '%') order by a.update_time desc limit 0, 10
执行结果
前面我们讲了,在SQL的LIKE语句中,%是一个通配符,它可以匹配任意数量(包括零个)的字符。
那 MySQL 是如何处理 %%0% 的呢?
它会将连续的%视为一个,因为它们的含义没有变化——仍然是匹配任意长度的字符序列。
- 'a.title LIKE '%0%':匹配任何包含0的a.title。
- 'a.title LIKE '%%0%':效果同上,多出来的%并不改变匹配模式。
- 'a.title LIKE '%%%0%%%':即使更多的%被添加进来,匹配模式仍然相同。
我们来验证一下,查询 %01%、%%01%、%%%01%的结果是完全一样的,都是查询标题中包含“10”的文章。
所以,% 通配符可以连续出现,但是它们的含义是一样的,都是匹配任意长度的字符序列。这也是一个面试的考点,但实际使用中,应该尽量避免这种情况的出现,因为会让不懂的新手产生困惑。
_ 通配符
_ 通配符其实算是一个占位符,比如说我们要查询标题为“分表”、“分库”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '分_';
但它只会匹配一个字符,所以只能匹配“分表”或者“分库”,而不能匹配“分布式”。
假如标题有这么几个:
- 分表
- 分库
- 分布式
- MySQL 分库
- MySQL 分表
那么,title LIKE '分_' 就只会匹配到“分表”和“分库”,而不会匹配到“分布式”、“MySQL 分库”、“MySQL 分表”。
所以,_ 通配符在实际工作中并不常用。
转义通配符
如果我们要查询的字符串中本身就包含 % 或者 _,那么就需要对它们进行转义,否则会被误认为是通配符。
MySQL 使用 \ 作为转义字符,比如说,我们要查询标题中包含“%分布式%”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '%\%分布式\%%';
小结
这一节,我们学习了一些简单的 WHERE 条件查询,包括比较查询操作符、区间查询、枚举查询、NULL 查询、逻辑操作符、通配符查询等。
其中重点讲了 % 通配符的使用,包括 MyBatis 中的 # 和 $ 的区别,以及 MySQL 会如何处理连续的 % 通配符。
这两个都是面试中的考点,如果有时间的话,大家还是要结合源码进行深入拆解的,对提到编程功底也大有帮助。
今天的内容大家一定要掌握,尤其是 MyBatis 中 #和$的区别,以及 MySQL 会如何处理连续的%通配符。
在**上一篇 **中,我们学习了简单的 SELECT 查询,但没有带上查询条件。要知道,真实的业务场景中,数量会非常大,有些甚至会有几百万、几千万条数据,如果不带上查询条件,一次性把全部数据查出来是不太现实的。
所以,我们通常要求在执行 SELECT 查询时,都要带上查询条件。那这一节,我们就来学习一些简单的 WHERE 条件查询。
我们仍然以**技术派 **的文章表 article 为例,比如说我们要查找标题为“聊聊分库分表”的文章,可以这么写:
SELECT * FROM article WHERE title = '聊聊分库分表';
这其中的 WHERE title = '聊聊分库分表' 就是查询条件,title 是字段名,'聊聊分库分表' 是字段值。
比较查询操作符
除了上面提到的 = 操作符,MySQL 还提供了很多其他的比较查询操作符,常用的有以下几种:
比如说,我们要查找 user_id 大于 1000 的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id > 1000;
其他的我就不一一展示了,很简单,大家可以自己试试(也没必要 😂,知道有这么一些比较操作符就行了,用到的时候会用就 OK)
区间查询
假如说我们要查询 user_id 在 1000 到 2000 之间的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id >= 1000 AND user_id
如果 searchParams.title 不为空,就会拼接 % 通配符,实现模糊查询。
其中的 concat 方法是 MySQL 的字符串拼接函数。
是 MyBatis 中参数占位符的标记,用于预处理语句(PreparedStatement)中,以防止 SQL 注入攻击。当使用#{}来包裹一个参数时,MyBatis 会在执行 SQL 之前将该参数的值安全地填充到 SQL 语句中。
注意,这是一个考点。在面试中,可能会被问到 # 和 $ 的区别。
$ 也是 MyBatis 中参数占位符的标记,用于直接拼接 SQL 语句,不会进行预处理。当使用${}来包裹一个参数时,MyBatis 会直接将该参数的值拼接到 SQL 语句中。
#{} 和 ${} 的区别在于,#{} 是预处理,会对参数进行安全处理,而 ${} 是直接拼接,不会对参数进行处理。
MyBatis 中的 # 和 $
我们这里稍微拓展一丢丢,假如 mapper.xml 文件中的 SQL 语句是这样的:
select * from user where name = #{name};
那么它将被解析为:
select * from user where name = ?;
一个 #{} 会被解析为一个参数占位符 ?。
而如果 xml 中的 SQL 语句是这样的:
select * from user where name = '${name}';
当我们传入的参数是 name = "王二" 时,它将被解析为:
select * from user where name = '王二';
$ 会直接拼接参数的值,不会进行预处理。这就存在 SQL 注入的风险。
假如有这样的 SQL 语句:
select * from ${tableName} where name = #{name}
当 tableName 为 user; delete user; -- 时,它将被解析为:
select * from user; delete user; -- where name = ?;
-- 是 SQL 中的注释符,表示注释掉后面的内容。于是,一条本来是 SQL 查询的语句,变成了删除 user 表的语句。
这是万万不能够的,当然了,这里讲的很浅,我们单独留一个传送门(里面再细讲):
连续的%通配符
我们这里来实验一下,假如查询条件中包含 % 通配符,MyBatis 会如何解析呢?MySQL 的执行结果又会怎么样呢?
我们还是以**技术派实战项目 **为例,假如我们要查询标题中包含“%0”的文章。
MyBatis
先来看 MyBatis 生成的 SQL 语句:
我把关键的部分摘出来:
Preparing: select a.id from article a where a.title like concat('%', ?, '%') order by a.update_time desc limit ?, ?
Parameters: %0(String), 0(Long), 10(Long)
可以看到,#{}是通过占位符 ? 的方式进行拼接的。
MySQL
那最终 MySQL 执行的 SQL 语句又是什么样的?
我们可以通过打开 MySQL 的通用查询日志(General Query Log)来辅助我们完成这项工作。
- 可以通过 SHOW VARIABLES LIKE 'general_log'; 来查看通用查询日志是否开启。ON 为开启,OFF 为关闭。
- 可以通过 SHOW VARIABLES LIKE 'general_log_file'; 来查看通用查询日志的文件路径。
如果未开启的话,可以通过 SET GLOBAL general_log = 'ON'; 来开启通用查询日志。
然后执行上面的查询,就可以在通用查询日志中看到 MySQL 执行的 SQL 语句。
可以通过文本工具打开日志文件,拉到最后,就可以找到对应的 SQL 语句。我的是 macOS,所以直接用 vim 就可以打开。
可以看到,最终 MySQL 执行的 SQL 语句是这样的(省略部分 SQL 内容):
select a.id from article a where a.title like concat('%', '%0', '%') order by a.update_time desc limit 0, 10
执行结果
前面我们讲了,在SQL的LIKE语句中,%是一个通配符,它可以匹配任意数量(包括零个)的字符。
那 MySQL 是如何处理 %%0% 的呢?
它会将连续的%视为一个,因为它们的含义没有变化——仍然是匹配任意长度的字符序列。
- 'a.title LIKE '%0%':匹配任何包含0的a.title。
- 'a.title LIKE '%%0%':效果同上,多出来的%并不改变匹配模式。
- 'a.title LIKE '%%%0%%%':即使更多的%被添加进来,匹配模式仍然相同。
我们来验证一下,查询 %01%、%%01%、%%%01%的结果是完全一样的,都是查询标题中包含“10”的文章。
所以,% 通配符可以连续出现,但是它们的含义是一样的,都是匹配任意长度的字符序列。这也是一个面试的考点,但实际使用中,应该尽量避免这种情况的出现,因为会让不懂的新手产生困惑。
_ 通配符
_ 通配符其实算是一个占位符,比如说我们要查询标题为“分表”、“分库”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '分_';
但它只会匹配一个字符,所以只能匹配“分表”或者“分库”,而不能匹配“分布式”。
假如标题有这么几个:
- 分表
- 分库
- 分布式
- MySQL 分库
- MySQL 分表
那么,title LIKE '分_' 就只会匹配到“分表”和“分库”,而不会匹配到“分布式”、“MySQL 分库”、“MySQL 分表”。
所以,_ 通配符在实际工作中并不常用。
转义通配符
如果我们要查询的字符串中本身就包含 % 或者 _,那么就需要对它们进行转义,否则会被误认为是通配符。
MySQL 使用 \ 作为转义字符,比如说,我们要查询标题中包含“%分布式%”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '%\%分布式\%%';
小结
这一节,我们学习了一些简单的 WHERE 条件查询,包括比较查询操作符、区间查询、枚举查询、NULL 查询、逻辑操作符、通配符查询等。
其中重点讲了 % 通配符的使用,包括 MyBatis 中的 # 和 $ 的区别,以及 MySQL 会如何处理连续的 % 通配符。
这两个都是面试中的考点,如果有时间的话,大家还是要结合源码进行深入拆解的,对提到编程功底也大有帮助。
今天的内容大家一定要掌握,尤其是 MyBatis 中 #和$的区别,以及 MySQL 会如何处理连续的%通配符。
在**上一篇 **中,我们学习了简单的 SELECT 查询,但没有带上查询条件。要知道,真实的业务场景中,数量会非常大,有些甚至会有几百万、几千万条数据,如果不带上查询条件,一次性把全部数据查出来是不太现实的。
所以,我们通常要求在执行 SELECT 查询时,都要带上查询条件。那这一节,我们就来学习一些简单的 WHERE 条件查询。
我们仍然以**技术派 **的文章表 article 为例,比如说我们要查找标题为“聊聊分库分表”的文章,可以这么写:
SELECT * FROM article WHERE title = '聊聊分库分表';
这其中的 WHERE title = '聊聊分库分表' 就是查询条件,title 是字段名,'聊聊分库分表' 是字段值。
比较查询操作符
除了上面提到的 = 操作符,MySQL 还提供了很多其他的比较查询操作符,常用的有以下几种:
比如说,我们要查找 user_id 大于 1000 的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id > 1000;
其他的我就不一一展示了,很简单,大家可以自己试试(也没必要 😂,知道有这么一些比较操作符就行了,用到的时候会用就 OK)
区间查询
假如说我们要查询 user_id 在 1000 到 2000 之间的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE user_id >= 1000 AND user_id
如果 searchParams.title 不为空,就会拼接 % 通配符,实现模糊查询。
其中的 concat 方法是 MySQL 的字符串拼接函数。
是 MyBatis 中参数占位符的标记,用于预处理语句(PreparedStatement)中,以防止 SQL 注入攻击。当使用#{}来包裹一个参数时,MyBatis 会在执行 SQL 之前将该参数的值安全地填充到 SQL 语句中。
注意,这是一个考点。在面试中,可能会被问到 # 和 $ 的区别。
$ 也是 MyBatis 中参数占位符的标记,用于直接拼接 SQL 语句,不会进行预处理。当使用${}来包裹一个参数时,MyBatis 会直接将该参数的值拼接到 SQL 语句中。
#{} 和 ${} 的区别在于,#{} 是预处理,会对参数进行安全处理,而 ${} 是直接拼接,不会对参数进行处理。
MyBatis 中的 # 和 $
我们这里稍微拓展一丢丢,假如 mapper.xml 文件中的 SQL 语句是这样的:
select * from user where name = #{name};
那么它将被解析为:
select * from user where name = ?;
一个 #{} 会被解析为一个参数占位符 ?。
而如果 xml 中的 SQL 语句是这样的:
select * from user where name = '${name}';
当我们传入的参数是 name = "王二" 时,它将被解析为:
select * from user where name = '王二';
$ 会直接拼接参数的值,不会进行预处理。这就存在 SQL 注入的风险。
假如有这样的 SQL 语句:
select * from ${tableName} where name = #{name}
当 tableName 为 user; delete user; -- 时,它将被解析为:
select * from user; delete user; -- where name = ?;
-- 是 SQL 中的注释符,表示注释掉后面的内容。于是,一条本来是 SQL 查询的语句,变成了删除 user 表的语句。
这是万万不能够的,当然了,这里讲的很浅,我们单独留一个传送门(里面再细讲):
连续的%通配符
我们这里来实验一下,假如查询条件中包含 % 通配符,MyBatis 会如何解析呢?MySQL 的执行结果又会怎么样呢?
我们还是以**技术派实战项目 **为例,假如我们要查询标题中包含“%0”的文章。
MyBatis
先来看 MyBatis 生成的 SQL 语句:
我把关键的部分摘出来:
Preparing: select a.id from article a where a.title like concat('%', ?, '%') order by a.update_time desc limit ?, ?
Parameters: %0(String), 0(Long), 10(Long)
可以看到,#{}是通过占位符 ? 的方式进行拼接的。
MySQL
那最终 MySQL 执行的 SQL 语句又是什么样的?
我们可以通过打开 MySQL 的通用查询日志(General Query Log)来辅助我们完成这项工作。
- 可以通过 SHOW VARIABLES LIKE 'general_log'; 来查看通用查询日志是否开启。ON 为开启,OFF 为关闭。
- 可以通过 SHOW VARIABLES LIKE 'general_log_file'; 来查看通用查询日志的文件路径。
如果未开启的话,可以通过 SET GLOBAL general_log = 'ON'; 来开启通用查询日志。
然后执行上面的查询,就可以在通用查询日志中看到 MySQL 执行的 SQL 语句。
可以通过文本工具打开日志文件,拉到最后,就可以找到对应的 SQL 语句。我的是 macOS,所以直接用 vim 就可以打开。
可以看到,最终 MySQL 执行的 SQL 语句是这样的(省略部分 SQL 内容):
select a.id from article a where a.title like concat('%', '%0', '%') order by a.update_time desc limit 0, 10
执行结果
前面我们讲了,在SQL的LIKE语句中,%是一个通配符,它可以匹配任意数量(包括零个)的字符。
那 MySQL 是如何处理 %%0% 的呢?
它会将连续的%视为一个,因为它们的含义没有变化——仍然是匹配任意长度的字符序列。
- 'a.title LIKE '%0%':匹配任何包含0的a.title。
- 'a.title LIKE '%%0%':效果同上,多出来的%并不改变匹配模式。
- 'a.title LIKE '%%%0%%%':即使更多的%被添加进来,匹配模式仍然相同。
我们来验证一下,查询 %01%、%%01%、%%%01%的结果是完全一样的,都是查询标题中包含“10”的文章。
所以,% 通配符可以连续出现,但是它们的含义是一样的,都是匹配任意长度的字符序列。这也是一个面试的考点,但实际使用中,应该尽量避免这种情况的出现,因为会让不懂的新手产生困惑。
_ 通配符
_ 通配符其实算是一个占位符,比如说我们要查询标题为“分表”、“分库”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '分_';
但它只会匹配一个字符,所以只能匹配“分表”或者“分库”,而不能匹配“分布式”。
假如标题有这么几个:
- 分表
- 分库
- 分布式
- MySQL 分库
- MySQL 分表
那么,title LIKE '分_' 就只会匹配到“分表”和“分库”,而不会匹配到“分布式”、“MySQL 分库”、“MySQL 分表”。
所以,_ 通配符在实际工作中并不常用。
转义通配符
如果我们要查询的字符串中本身就包含 % 或者 _,那么就需要对它们进行转义,否则会被误认为是通配符。
MySQL 使用 \ 作为转义字符,比如说,我们要查询标题中包含“%分布式%”的文章,可以这么写:
SELECT title, user_id, create_time FROM article WHERE title LIKE '%\%分布式\%%';
小结
这一节,我们学习了一些简单的 WHERE 条件查询,包括比较查询操作符、区间查询、枚举查询、NULL 查询、逻辑操作符、通配符查询等。
其中重点讲了 % 通配符的使用,包括 MyBatis 中的 # 和 $ 的区别,以及 MySQL 会如何处理连续的 % 通配符。
这两个都是面试中的考点,如果有时间的话,大家还是要结合源码进行深入拆解的,对提到编程功底也大有帮助。
知识星球
扫码加入星球
查看更多优质内容
https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412