问题
今天遇到一个线上问题,排查过程中发现,MySQL 查询条件使用字符串判断等时会自动忽略字符串尾部的空格,示例如下:
MySQL 表格结构:
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
新增数据,注意 name 传的是 “AAA ”,尾部两个空格:
INSERT INTO `test1`.`users`(`id`, `name`, `age`) VALUES (1, 'AAA ', 30);
当执行查询操作时,竟然查出了数据:
SELECT name, LENGTH(`name`) from users where name = 'AAA';
又试了当条件中空格在右时,可以匹配到数据:
当条件中空格在左时,又匹配不到数据:
原来,MySQL 在进行字符串比较时,默认情况下是对空格不敏感的,这与 MySQL 的 SQL 模式设置有关。
当使用=
进行字符串比较时,如果字符串右侧包含空格,MySQL 会自动忽略这些空格。也就是说,在默认的 MySQL 配置下,'AAA'
和 'AAA '
被认为是相等的。因此,在执行查询时:
SELECT name, LENGTH(`name`) FROM users WHERE name = 'AAA';
可以查到存储在数据库中 name = 'AAA '
的数据。这是因为MySQL在比较时忽略了尾随空格。
为什么会这样?
MySQL 在进行字符串比较时遵循以下规则:
- 对于
CHAR
类型字段,存储时会自动删除尾随空格。 - 对于
VARCHAR
类型字段,在比较时会忽略尾随空格。
这种行为是因为 SQL 标准允许在字符串比较中忽略尾随空格。
如何避免这个问题?
如果你需要严格区分尾随空格,可以使用以下方法:
-
使用二进制比较:可以使用
BINARY
关键字进行严格比较。SELECT name, LENGTH(`name`) FROM users WHERE BINARY name = 'AAA';
这样,MySQL会按照二进制字节逐个比较,尾随空格也不会被忽略。
-
使用
LIKE
进行精确匹配:SELECT name, LENGTH(`name`) FROM users WHERE name LIKE 'AAA';
LIKE
运算符在处理尾随空格时也会更严格。 -
显式地处理空格:可以通过
TRIM
函数显式去掉空格后再进行比较:SELECT name, LENGTH(`name`) FROM users WHERE TRIM(name) = 'AAA';
总结
MySQL默认在字符串比较中忽略尾随空格,如果需要进行严格匹配,可以使用BINARY
、LIKE
或者显式处理空格的方法。