网站开发网站开发,wordpress关闭前台编辑功能,如何优化网站 提高排名,深圳建设集团怎么样问题描述
最近碰到到一个奇怪的问题#xff0c;update 语句执行没有报错#xff0c;但是没有更新数据#xff0c;具体有问题的语句类似于如下形式#xff1a;
update test.stu set cname 0 and math 90 and his 80 where id 100;
复制
原因分析
直观上看#xff…问题描述
最近碰到到一个奇怪的问题update 语句执行没有报错但是没有更新数据具体有问题的语句类似于如下形式
update test.stu set cname 0 and math 90 and his 80 where id 100;
复制
原因分析
直观上看这个 update 语句的语法是有问题的正常更新多列数据的语法应该是用逗号类似于如下形式
update test.stu set cname 0,math 90,his 80 where id 100;
复制
直接用 and 第一反应其实是会报语法错误不太像是能正常执行的。那么基于云数据库 MySQL实际构造一个简单的场景尝试复现一下这个问题。
SQL 语句如下
CREATE TABLE stu (id int(11) NOT NULL,sname varchar(16) NOT NULL,cname varchar(8) DEFAULT NULL,math int(11) NOT NULL,eng int(11) DEFAULT NULL,his int(11) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4;insert into stu values(100,sam,0,90,88,83);
insert into stu values(101,jhon,1,97,82,81);
insert into stu values(102,mary,2,87,89,92);
insert into stu values(103,adam,2,87,89,92);
复制
然后分别试一试正常的 update 语句和使用 and 的 update 语句看一下实际的运行结果
mysql begin;
Query OK, 0 rows affected (0.00 sec)mysql update test.stu set cname 0 and math 90 and his 80 where id 100;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0mysql select * from stu;
-------------------------------------
| id | sname | cname | math | eng | his |
-------------------------------------
| 100 | sam | 0 | 90 | 88 | 83 |
| 101 | jhon | 1 | 97 | 82 | 81 |
| 102 | mary | 2 | 87 | 89 | 92 |
| 103 | adam | 2 | 87 | 89 | 92 |
-------------------------------------
4 rows in set (0.00 sec)mysql update test.stu set cname 0,math 90,his 80 where id 100;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql select * from stu;
-------------------------------------
| id | sname | cname | math | eng | his |
-------------------------------------
| 100 | sam | 0 | 90 | 88 | 80 |
| 101 | jhon | 1 | 97 | 82 | 81 |
| 102 | mary | 2 | 87 | 89 | 92 |
| 103 | adam | 2 | 87 | 89 | 92 |
-------------------------------------
4 rows in set (0.00 sec)mysql rollback;
Query OK, 0 rows affected (0.01 sec)mysql
复制
可以看到这两个语句确实都不会报错且带 and 的 update 语句匹配到了具体的行Rows matched: 1但是没有修改数据Changed: 0标准语法下的 update 语句倒是正常修改了数据。
由此可见MySQL 在语法上并不认为 and 这个用法是错误的那么说明 MySQL 用另外的方式“解读”了这个语句。最容易想到的就是 MySQL 是不是在 set 的时候把 and 解释成了逻辑运算符而不是英文意义上的“和”而且 cname 的取值本来就是 0也符合数据库处理 bool 数据时的行为用 0 和 1 代替 False 和 True。
验证起来很简单换个 cname 不为 0 的数据 update 一下就可以了
mysql select * from stu;
-------------------------------------
| id | sname | cname | math | eng | his |
-------------------------------------
| 100 | sam | 0 | 90 | 88 | 83 |
| 101 | jhon | 1 | 97 | 82 | 81 |
| 102 | mary | 2 | 87 | 89 | 92 |
| 103 | adam | 2 | 87 | 89 | 92 |
-------------------------------------
4 rows in set (0.00 sec)mysql begin;update test.stu set cname 0 and math 90 and his 80 where id 101;
Query OK, 0 rows affected (0.00 sec)Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql select * from stu;
-------------------------------------
| id | sname | cname | math | eng | his |
-------------------------------------
| 100 | sam | 0 | 90 | 88 | 83 |
| 101 | jhon | 0 | 97 | 82 | 81 |
| 102 | mary | 2 | 87 | 89 | 92 |
| 103 | adam | 2 | 87 | 89 | 92 |
-------------------------------------
4 rows in set (0.00 sec)mysql rollback;
Query OK, 0 rows affected (0.00 sec)
复制
从结果来看MySQL 修改 cname 的值为 0说明确实是当成逻辑运算符来处理了仔细分析这个语句会发现 MySQL 按照如下方式来处理
set cname (0 and math 90 and his 80)
复制
math 和 his 的取值是根据 where 条件筛选的行来决定的实际对应到上面测试的场景会变成如下的逻辑判断
0 and 97 90 and 81 80
复制
PS需要注意即便是字符型的数据 0也会被当做 False。
解决方案
目前并不能通过 sql_mode 或者其他参数的形式来阻止这种带 and 的 update 语句因此这一类问题的隐蔽性比较强。建议在开发的时候利用封装好的框架或者加强代码或者 SQL review 来避免这个问题。