《Mysql学习MySQL的隐式类型转换整理总结》要点:
本文介绍了Mysql学习MySQL的隐式类型转换整理总结,希望对您有用。如果有疑问,可以联系我们。
MYSQL实例前言
MYSQL实例前几天在看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下.希望对大家有所帮助.
MYSQL实例当我们对不同类型的值进行比较的时候,为了使得这些数值「可比较」(也可以称为类型的兼容性),MySQL会做一些隐式转化(Implicit type conversion).
MYSQL实例比如下面的例子:
MYSQL实例
mysql> SELECT 1+'1';
-> 2
mysql> SELECT CONCAT(2,' test');
-> '2 test'
MYSQL实例很明显,上面的SQL语句的执行过程中就出现了隐式转化.并且从结果们可以判断出,第一条SQL中,将字符串的“1”转换为数字1,而在第二条的SQL中,将数字2转换为字符串“2”.
MYSQL实例MySQL也提供了CAST()函数.我们可以使用它明确的把数值转换为字符串.当使用CONCA()
函数的时候,也可能会出现隐式转化,因为它希望的参数为字符串形式,但是如果我们传递的不是字符串呢:
MYSQL实例
mysql> SELECT 38.8, CAST(38.8 AS CHAR);
-> 38.8, '38.8'
mysql> SELECT 38.8, CONCAT(38.8);
-> 38.8, '38.8'
MYSQL实例隐式转化规则
MYSQL实例官方文档中关于隐式转化的规则是如下描述的:
MYSQL实例If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.
MYSQL实例翻译为中文就是:
MYSQL实例注意点
MYSQL实例安全问题:假如 password 类型为字符串,查询条件为 int 0 则会匹配上.
MYSQL实例
mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
+----+-------+-----------+
2 rows in set (0.00 sec)
mysql> select * from test where name = 'test1' and password = 0;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
+----+-------+-----------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'password1' |
+---------+------+-----------------------------------------------+
1 row in set (0.00 sec)
MYSQL实例相信上面的例子,一些机灵的同学可以发现其实上面的例子也可以做sql注入.
MYSQL实例假设网站的登录那块做的比较挫,使用下面的方式:
MYSQL实例
SELECT * FROM users WHERE username = '$_POST["username"]' AND password = '$_POST["password"]'
MYSQL实例如果username输入的是a' OR 1='1
,那么password随便输入,这样就生成了下面的查询:
MYSQL实例
SELECT * FROM users WHERE username = 'a' OR 1='1' AND password = 'anyvalue'
MYSQL实例就有可能登录系统.其实如果攻击者看过了这篇文章,那么就可以利用隐式转化来进行登录了.如下:
MYSQL实例
mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
| 3 | aaa | aaaa |
| 4 | 55aaa | 55aaaa |
+----+-------+-----------+
4 rows in set (0.00 sec)
mysql> select * from test where name = 'a' + '55';
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 4 | 55aaa | 55aaaa |
+----+-------+----------+
1 row in set, 5 warnings (0.00 sec)
MYSQL实例之所以出现上述的原因是因为:
MYSQL实例
mysql> select '55aaa' = 55;
+--------------+
| '55aaa' = 55 |
+--------------+
| 1 |
+--------------+
1 row in set, 1 warning (0.00 sec)
mysql> select 'a' + '55';
+------------+
| 'a' + '55' |
+------------+
| 55 |
+------------+
1 row in set, 1 warning (0.00 sec)
MYSQL实例下面通过一些例子来复习一下上面的转换规则:
MYSQL实例
mysql> select 1+1;
+-----+
| 1+1 |
+-----+
| 2 |
+-----+
1 row in set (0.00 sec)
mysql> select 'aa' + 1;
+----------+
| 'aa' + 1 |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)
MYSQL实例把字符串“aa”和1进行求和,得到1,因为“aa”和数字1的类型不同,MySQL官方文档告诉我们:
MYSQL实例 When an operator is used with operands of different types, type conversion occurs to make the operands compatible.
MYSQL实例查看warnings可以看到隐式转化把字符串转为了double类型.但是因为字符串是非数字型的,所以就会被转换为0,因此最终计算的是0+1=1
MYSQL实例上面的例子是类型不同,所以出现了隐式转化,那么如果我们使用相同类型的值进行运算呢?
MYSQL实例
mysql> select 'a' + 'b';
+-----------+
| 'a' + 'b' |
+-----------+
| 0 |
+-----------+
1 row in set, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |
+---------+------+---------------------------------------+
2 rows in set (0.00 sec)
MYSQL实例是不是有点郁闷呢?
MYSQL实例之所以出现这种情况,是因为+为算术操作符arithmetic operator 这样就可以解释为什么a和b都转换为double了.因为转换之后其实就是:0+0=0了.
MYSQL实例再看一个例子:
MYSQL实例
mysql> select 'a'+'b'='c';
+-------------+
| 'a'+'b'='c' |
+-------------+
| 1 |
+-------------+
1 row in set, 3 warnings (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'c' |
+---------+------+---------------------------------------+
3 rows in set (0.00 sec)
MYSQL实例现在就看也很好的理解上面的例子了吧.a+b=c结果为1,1在MySQL中可以理解为TRUE,因为'a'+'b'的结果为0,c也会隐式转化为0,因此比较其实是:0=0也就是true,也就是1.
MYSQL实例第二个需要注意点就是防止多查询或者删除数据
MYSQL实例
mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
| 3 | aaa | aaaa |
| 4 | 55aaa | 55aaaa |
| 5 | 1212 | aaa |
| 6 | 1212a | aaa |
+----+-------+-----------+
6 rows in set (0.00 sec)
mysql> select * from test where name = 1212;
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 5 | 1212 | aaa |
| 6 | 1212a | aaa |
+----+-------+----------+
2 rows in set, 5 warnings (0.00 sec)
mysql> select * from test where name = '1212';
+----+------+----------+
| id | name | password |
+----+------+----------+
| 5 | 1212 | aaa |
+----+------+----------+
1 row in set (0.00 sec)
MYSQL实例上面的例子本意是查询id为5的那一条记录,结果把id为6的那一条也查询出来了.我想说明什么情况呢?有时候我们的数据库表中的一些列是varchar类型,但是存储的值为‘1123'这种的纯数字的字符串值,一些同学写sql的时候又不习惯加引号.这样当进行select,update或者delete的时候就可能会多操作一些数据.所以应该加引号的地方别忘记了.
MYSQL实例关于字符串转数字的一些说明
MYSQL实例
mysql> select 'a' = 0;
+---------+
| 'a' = 0 |
+---------+
| 1 |
+---------+
1 row in set, 1 warning (0.00 sec)
mysql> select '1a' = 1;
+----------+
| '1a' = 1 |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (0.00 sec)
mysql> select '1a1b' = 1;
+------------+
| '1a1b' = 1 |
+------------+
| 1 |
+------------+
1 row in set, 1 warning (0.00 sec)
mysql> select '1a2b3' = 1;
+-------------+
| '1a2b3' = 1 |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> select 'a1b2c3' = 0;
+--------------+
| 'a1b2c3' = 0 |
+--------------+
| 1 |
+--------------+
1 row in set, 1 warning (0.00 sec)
MYSQL实例从上面的例子可以看出,当把字符串转为数字的时候,其实是从左边开始处理的.
MYSQL实例总结
MYSQL实例以上就是这篇文章的全部内容了,如果你有其他更好的例子,或者被隐式转化坑过的情况,欢迎分享.希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流.
转载请注明本页网址:
http://www.vephp.com/jiaocheng/3276.html