关于MySQL自动将varchar类型值的末尾空格不起作用的问题

背景

优化线上系统的一个查询方法,这里我举例说明。
方法的功能是返回所有异常涉及到的容器号,并对其去重。
原来的方法是返回符合要求的Dto对象集合,然后取Dto对象中的containerNo这个属性,通过map的key来实现去重操作;
现在的方法是在SQL层面只返回container_no字段,且通过DISTICT 对容器号去重。
SQL内容类似于:

select distinct name  from  `user`  where name  = 'zhang';

我们假设数据库中符合查询条件的容器号有以下几个:

  1. ZZW001
  2. ZZW002
  3. ZZW001 注意这里末尾有一个空格
  4. ZZW001 注意这里末尾假设有三个空格

那么新旧方法处理的结果是:

  • 旧方法:ZZW001 ZZW002 ZZW001 (注意这里末尾有一个空格) ZZW001 (注意这里末尾假设有三个空格)
  • 新方法:ZZW001 ZZW002

之所以这样,是因为MySQL将字符串后面的空格全给过滤了。
我也试了作为where 查询条件,一样是无效的,不过字符串前面的空格是起作用的,且末尾的空格是可以正常存储到数据库里的,即只有作为条件和数据处理对象时(比如去重),才会“失效”。

查阅了网上的资料,有人这么说:

如果字段是char或varchar类型,那么在字符串比较的时候MySQL使用PADSPACE校对规则,会忽略字段末尾的空格字符。

解决方案:

第一种方法:使用 like

select * from table where user like 'abcdefg ';

第二种方法:使用BINARY

select * from table where user = BINARY 'abcdefg ';

第三种方法:使用length函数

select * from table where user = 'abcdefg ' and length(user) = length('abcdefg ');

注意

如果程序没有对所有的业务场景做末尾空格的处理,那么建议后面的查询不要使用前面的解决方案来处理,否则容易出现问题,如果所有的业务场景在存储数据的时候,都做了末尾空格的处理,那么可以查询的时候可以使用上面的解决方案来实现数据精确查询。
其实对于数据的去重过滤如果数据不是特别的多,建议使用MySQL处理。以我们线上的这个问题为例,存储容器号到业务表的时候,可能是用户在末尾多输入一个空格,末尾多空格依然可以查出数据,这个时候校验就通过了,但是存到数据库的拿用户输入的存储的,即将末尾带有空格的存储了,如果后面使用前面的解决方案处理,就会出现问题,比如作为联表查询的时候关联条件时。
但是代码的去重都是强校验,末尾有空格和没有空格是两个不同的数据,所以就会出现最开始前面的背景问题。
最终,结合业务的分析,我们认为原来的方法是存在问题的,新方法在数据库去重是没问题的。

posted @ 2022-04-07 21:32  张志文的博客  阅读(604)  评论(0)    收藏  举报