6252 字
约 20 分钟
7
MySQL WHERE 条件查询,重点搞懂 % 通配符,MySQL 会如何处理连续的 % 通配符

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 中的 # 和 $

连续的%通配符

我们这里来实验一下,假如查询条件中包含 % 通配符,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 中的 # 和 $

连续的%通配符

我们这里来实验一下,假如查询条件中包含 % 通配符,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 中的 # 和 $

连续的%通配符

我们这里来实验一下,假如查询条件中包含 % 通配符,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
MySQL WHERE 条件查询,重点搞懂 % 通配符,MySQL 会如何处理连续的 % 通配符
https://clxhxhhr.top/posts/2598/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。