最近写过程时发现一个有趣的事情,mysql 的procedure 在传参的过程中,遇到一些“非法”的参数是有自己独特的处理方式。例如本来定义是int的参数,结果被传入的是null
,mysql 的procedure会正常执行。
库表结构:
create database db5;
use db5;
drop table if exists t;
create table t(
id int primary key auto_increment,
value int
);
create table t2(
id int primary key auto_increment,
value float
);
创建procedure:
delimiter //
create procedure p14 (in parameter1 int)
begin
declare variable1 int;
set variable1 = parameter1 + 1;
insert into t(value) values (variable1);
end;
//
delimiter ;
运行结果:
mysql> call p14(5);
query ok, 1 row affected (0.02 sec)
mysql> select * from t;
+----+-------+
| id | value |
+----+-------+
| 2 | 6 |
+----+-------+
1 row in set (0.00 sec)
mysql> call p14(null);
query ok, 1 row affected (0.04 sec)
mysql> select * from t;
+----+-------+
| id | value |
+----+-------+
| 2 | 6 |
| 3 | null |
+----+-------+
2 rows in set (0.00 sec)
大家注意到没有,当参数parameter1传入等于5时,表插入6,数据正常。
当参数parameter1传入为null时,表插入null,这是为什么呢。
关于这点大家可以看看声明变量的语句,文档给出了这样的解释:declare这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个default子句。值可以被指定为一个表达式,不需要为一个常数。如果没有default子句,初始值为null。
上面这样又有了一个新的问题:null=null+1?哈哈,有点意思了,此时的set variable1 = parameter1 + 1;会有一个怎样合理的解释呢?
这是王老师给的解释(第二条很经典呀~~~):
1 null+1=null
因为null表现为“类似指针”,也就是指向“0地址的内容”,如果这个内容为“null”,则表现为null。这就是指定int也为空的原因。但是,如果“内容”有值,则表现为不空,对于mysql而言,是个“随机数”或0;当这个地址内容存储时,值就固定了;
2 如果a=b+1,只有b为null时,a才为null;set a=b+1,是否可理解为set (b+1),a已经在‘当前’替换,这样a是谁不重要,重要的是b+1;
本想法没有验证,主要是分离不了set,而mysql5的文档,有支持这一说法,但英文版本是用“替换”,不是中文的“设置”表达,感觉意思更为接近!(set)
一个新的问题:当a=1/b,b=0时,也能运行成功吗?
mysql>
delimiter //
create procedure p15 (in parameter1 int)
begin
declare variable2 float(5,3);
set variable2 =1/ parameter1;
insert into t2(value) values (variable2);
end;
//
delimiter ;
执行结果:
mysql> call p15(0);
query ok, 1 row affected (0.03 sec)
mysql> select * from t2;
+----+-------+
| id | value |
+----+-------+
| 1 | null |
+----+-------+
1 row in set (0.00 sec)
mysql> call p15(1);
query ok, 1 row affected (0.03 sec)
mysql> select * from t2;
+----+-------+
| id | value |
+----+-------+
| 1 | null |
| 2 | 1 |
读者注意没有? 这个也能运行成功。其实这个问题在mysql的sql服务器模式参数细节中可以找到。
mysql服务器可以以不同的sql模式来操作,并且可以为不同客户端应用不同模式。这样每个应用程序可以根据自己的需求来定制服务器的操作模式。
模式定义mysql应支持哪些sql语法,以及应执行哪种数据验证检查。这样可以更容易地在不同的环境中使用mysql,并结合其它数据库服务器使用mysql。
你可以用--sql-mode="modes"选项启动mysqld来设置默认sql模式。如果你想要重设,该值还可以为空(--sql-mode ="")。
你还可以在启动后用set [session|global] sql_mode='modes'语句设置sql_mode变量来更改sql模式。设置 global变量时需要拥有super权限,并且会影响从那时起连接的所有客户端的操作。设置session变量只影响当前的客户端。任何客户端可以随时更改自己的会话 sql_mode值。
modesis是用逗号(‘,’)间隔开的一系列不同的模式。你可以用select @@sql_mode语句查询当前的模式。默认值是空(没有设置任何模式)。
strict_trans_tables
为所有存储引擎启用严格模式。非法数据值被拒绝。后面有详细说明。
· strict_trans_tables
为事务存储引擎启用严格模式,也可能为非事务存储引擎启用严格模式。后面有详细说明。
严格模式控制mysql如何处理非法或丢失的输入值。有几种原因可以使一个值为非法。例如,数据类型错误,不适合列,或超出范围。当新插入的行不包含某列的没有显示定义default子句的值,则该值被丢失。
对于事务表,当启用strict_all_tables或strict_trans_tables模式时,如果语句中有非法或丢失值,则会出现错误。语句被放弃并滚动。
对于非事务表,如果插入或更新的第1行出现坏值,两种模式的行为相同。语句被放弃,表保持不变。如果语句插入或修改多行,并且坏值出现在第2或后面的行,结果取决于启用了哪个严格选项:
error_for_division_by_zero
在严格模式,在insert或update过程中,如果被零除(或mod(x,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时mysql返回null。如果用到insert ignore或update ignore中,mysql生成被零除警告,但操作结果为null。
还有些其他参数,读者可以参详mysql的文档。
当我们给sql_mode 中加入error_for_division_by_zero参数时,重启mysql
mysql> show variables like 'sql_mode';
+---------------+---------------------------------------------------------------
----------------------------+
| variable_name | value
|
+---------------+---------------------------------------------------------------
----------------------------+
| sql_mode | strict_trans_tables,error_for_division_by_zero,no_auto_create_
user,no_engine_substitution |
+---------------+---------------------------------------------------------------
----------------------------+
1 row in set (0.00 sec)
mysql> select 1/0;
+------+
| 1/0 |
+------+
| null |
+------+
1 row in set, 1 warning (0.00 sec)
我们看到了1 warning,我们在看下这个warning:
mysql> show warnings;
+-------+------+---------------+
| level | code | message |
+-------+------+---------------+
| error | 1365 | division by 0 |
+-------+------+---------------+
1 row in set (0.00 sec)
mysql> exit
bye
我们把sql_mode 中去掉error_for_division_by_zero参数时,重启mysql,试试看:
c:\documents and settings\administrator>net stop mysql
mysql 服务正在停止.
mysql 服务已成功停止。
c:\documents and settings\administrator>net start mysql
mysql 服务已经启动成功。
mysql> select 1/0;
+------+
| 1/0 |
+------+
| null |
+------+
1 row in set (0.00 sec)
mysql> show warnings;
empty set (0.02 sec)
这时warnings的内容为空。
问题到这里,读者也知道这是为什么了。有空再试试别的数据库,看看也是不是这样
0
0
相关文章
mysql FIND IN SET是什么_mysql字符串集合函数讲解
mysql中使用临时表优化查询与索引效率
mysql如何使用coalesce_mysql空值处理函数解析
mysql中自动递增字段与索引优化
mysql如何管理历史备份文件_mysql备份策略说明
相关标签:
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。
91
2026.02.02
本专题聚合极兔快递、京东快递、中通快递、圆通快递、韵达快递等主流物流平台的单号查询与运单追踪内容,重点解决单号查询、手机号查物流、官网入口直达、包裹进度实时追踪等高频问题,帮助用户快速获取最新物流状态,提升查件效率与使用体验。
27
2026.02.02
本专题系统讲解 Golang 在 WebAssembly(WASM)开发中的实践方法,涵盖 WASM 基础原理、Go 编译到 WASM 的流程、与 JavaScript 的交互方式、性能与体积优化,以及典型应用场景(如前端计算、跨平台模块)。帮助开发者掌握 Go 在新一代 Web 技术栈中的应用能力。
11
2026.02.02
本专题聚焦 PHP Swoole 扩展在高性能服务端开发中的应用,系统讲解协程模型、异步IO、TCP/HTTP/WebSocket服务器、进程与任务管理、常驻内存架构设计。通过实战案例,帮助开发者掌握 使用 PHP 构建高并发、低延迟服务端应用的工程化能力。
5
2026.02.02
本专题系统讲解 Java 通过 JNI 调用 C/C++ 本地代码的核心机制,涵盖 JNI 基本原理、数据类型映射、内存管理、异常处理、性能优化策略以及典型应用场景(如高性能计算、底层库封装)。通过实战示例,帮助开发者掌握 Java 与本地代码混合开发的完整流程。
5
2026.02.02
热门下载
相关下载
精品课程




