一个 MySQL 隐式转换的坑,差点把服务器整崩溃了( 二 )


我的第一感觉是,不仅不会查出数据,而且还会报错,因为连接的这两个字段类型都不一样,值更不一样 。
结果却被啪啪打脸,不仅没有报错,而且还查出了数据 。

一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
可以把这个问题简化一下,简化成下面这条语句,同样也会出现问题 。
select * from `order` where order_code = 1;
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
明明这条记录的 order_code 字段的值是 1d90530e-6ada-47c1-b2fa-adba4545aabd,怎么用 order_code=1的条件就把它给查出来了 。
根源所在相信有的同学已经猜出来了,这里是 MySQL 进行了隐式转换,由于查询条件后面跟的查询值是整型的,所以 MySQL 将 order_code字段进行了字符串到整数类型的转换,而转换后的结果正好是 1
通过 cast函数转换验证一下结果 。
select cast('1d90530e-6ada-47c1-b2fa-adba4545aabd' as unsigned);
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
再用两条 SQL 看一下字符串到整数类型转换的规则 。
select cast('223kkk' as unsigned);select cast('k223kkk' as unsigned);
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
223kkk转换后的结果是 223,而k223kkk转换后的结果是0 。总结一下,转换的规则是:
1、从字符串的左侧开始向右转换,遇到非数字就停止;
2、如果第一个就是非数字,最后的结果就是0;
隐式转换的规则当操作符与不同类型的操作数一起使用的时候,就会发生隐式转换 。
例如算数运算符的前后是不同类型时,会将非数字类型转换为数字,比如 '5a'+2,就会将5a转换为数字类型,然后和2相加,最后的结果就是 7。
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
再比如 concat函数是连接两个字符串的,当此函数的参数出现非字符串类型时,就会将其转换为字符串,例如concat(88,'就是发'),最后的结果就是 88就是发
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

文章插图
MySQL 官方文档有以下几条关于隐式转换的规则:
1、两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换;
也就是两个参数中如果只有一个是NULL,则不管怎么比较结果都是 NULL,而两个 NULL 的值不管是判断大于、小于或等于,其结果都是1 。
2、两个参数都是字符串,会按照字符串来比较,不做类型转换;
3、两个参数都是整数,按照整数来比较,不做类型转换;
4、十六进制的值和非数字做比较时,会被当做二进制字符串;
例如下面这条语句,查询 user 表中name字段是 0x61 的记录,0x是16进制写法,其对应的字符串是英文的 'a',也就是它对应的 ASCII 码 。
select * from user where name = 0x61;所以,上面这条语句其实等同于下面这条
select * from user where name = 'a';可以用 select 0x61;验证一下 。
5、有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 时间戳;
例如下面这两条SQL,都是将条件后面的值转换为时间戳再比较了,只不过
一个 MySQL 隐式转换的坑,差点把服务器整崩溃了

经验总结扩展阅读