【MySQL】变量与报错处理

本文详细介绍了MySQL中变量的分类(系统变量和用户变量),包括全局变量、会话变量的使用方法,以及如何定义和处理存储过程中的条件和错误。重点讲解了如何设置、查看和修改变量值,以及在遇到错误时的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、变量

在MySQL的存储过程与函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据。它可以分为用户自定义变量系统变量

1、系统变量

1)系统变量分为全局变量(需要使用关键字global)和会话系统变量(需要使用关键字session),如果没有声明global,那默认是session级别的变量

  • 全局系统变量对所有会话(连接)都有效,但是重启后就会重置(但是在MySQL8.0中,可以使用关键字PERSIST进行持久化,也就是SET GLOBAL 变量名 = 变量值;的形式,即使MySQL服务器重启,这个全局变量也不会变回去)
  • 会话系统变量仅针对当前会话(连接)有效。会话期间,当前会话对某个会话系统变量的修改,并不会影响其他会话中同一会话系统变量的值。而且会话重新连接之后,变量值也会重置
  • 会话1修改了某个全局系统变量会影响到会话2中同一全局系统变量

2)MySQL中有些变量只能是全局系统变量,例如max_connection用于限制服务器的最大连接数
有些系统变量既可以是全局的又可以是会话级别的,如character_client_set用于设置客户端的字符集
有些系统变量只能是会话级别的,例如pseudo_thread_id用于标记当前会话的MySQL连接id

3)查看系统变量

# 查看所有全局变量
SHOW GLOBAL VARIABLES;

# 查看所有会话变量
SHOW SESSION VARIABLES;
或者
SHOW VARIABLES;

# 查看满足条件的部分全局系统变量
SHOW GLOBAL VARIABLES LIKE '%标识符%';

# 查看满足条件的部分会话系统变量
SHOW SESSION VARIABLES LIKE '%标识符%';
或者
SHOW VARIABLES LIKE '%标识符%';

# 查看指定全局系统变量
SELECT @@global.变量名;

# 查看指定会话系统变量
SELECT @@session.变量名;
或者
SELECT @@变量名;  #不声明全局还是会话级别的情况下,会先去会话系统变量中找,如果没有再去全局系统变量中找

4)修改系统变量

  • 方式一:修改MySQL的配置文件,但是需要重启服务
  • 方式二:使用set命令重新设置系统变量的值
# 修改全局系统变量值
SET @@global.变量名 = 变量值;
或者
SET GLOBAL 变量名 = 变量值;

# 修改会话系统变量值
SET @@session.变量名 = 变量值;
或者
SET SESSION 变量名 = 变量值;

2、用户变量

1)用户变量是用户自己定义的,MySQL中用户变量以@开头进行定义。根据作用范围的不同分为会话用户变量局部变量

  • 会话用户变量:作用域和会话变量一样,只对当前连接会话有效。注意和会话系统变量区分开
  • 局部变量:只在BEGIN和END语句块中有效,只能在存储过程和函数中使用

2)会话用户变量的使用

声明和赋值

# 方式一:使用=或者:=
SET @用户变量 =;
SET @用户变量 :=;

# 方式二:使用:=或者INTO关键字,就相当于在查询语句中插入一段用户变量的声明,方式二不能使用=
SELECT @用户变量 := 表达式 [FROM 等子句];
SELECT 表达式 INTO @用户变量 [FROM 等子句];
#例如
SELECT @A1 := COUNT(*) FROM t_test;
SELECT AVG(salary) INTO @A2 FROM t_employee;

查询

SELECT @用户变量;

3)局部变量

  • 相关关键字:使用关键字DECLARE进行定义,使用SET进行赋值,使用SELECT进行查询
  • 作用域:仅在定义它的BEGIN...END之间有效,即存储过程、函数中
  • 位置:只能放在BEGIN...END中,且只能放在第一句

定义变量,如果不声明默认值,那么初始值为null

DECLARE 变量名 类型 [default]; 
例如
DECLARE v1 INT DEFAULT 100;

变量赋值

# 方式一:使用=或者:=
SET 局部变量 =;
SET 局部变量 :=;

# 方式二:使用INTO关键字,就相当于在查询语句中插入一段用户变量的声明
SELECT 字段或表达式 INTO 局部变量 FROM;
#例如
SELECT AVG(salary) INTO A2 FROM t_employee;

变量的使用

SELECT 局部变量名;

它是怎么在存储过程、函数中进行使用的呢?

DELIMITER $

CREATE PROCEDURE test_var()
BEGIN
	# 变量声明,如果a,b默认值都是0,可以使用DECLARE a,b INT DEFAULT 0来声明
	DECLARE a INT DEFAULT 0;
	DECLARE b INT;
	DECLARE c VARCHAR(25);

	# 变量赋值
	SET a = 1;
	SET b := 2;
	SELECT emp_name INTO c FROM t_emp WHERE emp_id = 101;

	# 变量使用
	SELECT a,b,c;
END $

DELIMITER ;

# 调用存储过程
CALL test_var();

4)用户变量(包括会话用户变量、局部变量)和系统变量的区别

  • 声明方面:
    • 用户变量:
      • 会话用户变量的声明和使用需要带一个@
      • 局部变量不需要带@,但是局部变量的定义需要使用关键字DECLAER
    • 系统变量如果使用时带@符号需要带2个
  • 定义位置:
    • 会话用户变量可以定义在任何地方
    • 局部变量只能放在BEGIN...END中,且只能放在第一句
  • 作用域:
    • 会话用户变量:当前会话
    • 局部变量:定义它的BEGIN...END

二、定义条件与处理程序

定义条件:指事先定义程序执行过程中可能遇到的问题
处理程序:定义了在遇到问题之后的处理方式,保证了存储过程或者存储函数在遇到警告或者错误时能继续执行,增强了其处理问题的能力,避免程序因异常停止运行

定义条件处理程序存储函数、存储过程中都是支持的

1、定义条件

假设我们有一个学生表t_student
它有2个字段,stu_id和stu_name,其中stu_id在声明的时候就加了非空约束

DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student`  (
  `stu_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '学生id',
  `stu_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '学生姓名'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


INSERT INTO `t_student` VALUES ('001', 'jack');
INSERT INTO `t_student` VALUES ('002', 'rose');

按照我们的认知,加了非空限制的字段不管是更新还是新增,都不应该支持null做值
但是,我测试的时候发现了一个很神奇的现象
这里的stu_id被我更新成null了!!
在这里插入图片描述
后来排查一番发现是我的MySQL数据库缺少STRICT_TRANS_TABLES(严格模式)配置
改完再重启mysql服务就好了
在这里插入图片描述
在这里插入图片描述

言归正传,我们声明一个存储过程,将t_student中的stu_id更新为null

DELIMITER //
CREATE PROCEDURE testExecption()
	BEGIN
		SET @X = 1;
		UPDATE t_student set stu_id = NULL where stu_name = 'jack';
		SET @X = 2;
		UPDATE t_student set stu_id = '001' where stu_name = 'jack';
		SET @X = 3;
	END //
DELIMITER ;

# 调用存储过程
call testExecption();

# 查询变量X
select @X;

调用存储过程,发现报错如下
在这里插入图片描述
在这里插入图片描述
这里的1048和23000就是错误码
1048是MySQL_error_code,他是数值类型错误代码
23000是sqlstate_value,它是长度为5的字符串类型错误代码

1)定义条件就是给MySQL中错误码命名。它将一个错误名字指定的错误条件进行关联
这个名字可以随后被用在定义处理程序的DECALRE HANDLER语句中,

定义条件不是必要的,只有在处理程序中需要用到的时候才要去定义

定义条件使用DECLARE关键字,语法为

DECLARE 错误名称 CONDITION FOR 错误码(或者错误条件);

举例:我们现在要使用Field_Not_Be_Null这个错误名称来与MySQL中违反非空约束的错误类型ERROR 1048 (23000)进行对应

# 方式一:使用MySQL_error_code
DECLARE Field_Not_Be_Null CONDITION FOR 1048;
# 方式二:使用sqlstate_value
DECLARE Field_Not_Be_Null CONDITION FOR SQLSTATE '23000';

2、定义处理程序

1)定义语法

DECLARE 处理方式 HANDLER FOR 错误类型 处理语句;

处理方式:

  • CONTINUE:遇到指定的错误类型不处理,继续往下执行
  • EXIT:遇到指定的错误类型马上退出
  • UNDO:遇到指定的错误类型撤回之前的操作,MySQL中暂时不支持

错误类型:

  • MySQL_error_code
  • sqlstate_value
  • 错误名称:上面定义条件里声明的错误名称
  • SQLWARNING:匹配所有01开头的sqlstate错误码
  • NOT FOUND:匹配所有02开头的sqlstate错误码
  • SQLEXCEPTION:匹配所有没被SQLWARNING和NOT FOUND捕获的sqlstate错误码

处理语句:

  • 可以是SET 变量 = 值这样的简单语句
  • 也可以是BEGIN...END编写的符合语句

接下来,我们看下如何使用上面说的6种错误类型来定义处理程序

# 捕获MySQL_error_code
DECLARE CONTINUE HANDLER FOR 1048 SET @result = 'Column stu_id cannot be null';

# 捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @result = 'Column stu_id cannot be null';

# 先定义条件,再调用错误类型
DECLARE Field_Not_Be_Null CONDITION FOR 1048;
DECLARE CONTINUE HANDLER FOR Field_Not_Be_Null SET @result = 'Column stu_id cannot be null';

# 使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @result = 'Column stu_id cannot be null';

# 使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @result = 'Column stu_id cannot be null';

# 使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @result = 'Column stu_id cannot be null';

2)案例处理
掌握了定义条件与处理程序之后
我们怎么处理上面更新t_student中stu_id为null时执行报错的问题呢

DROP PROCEDURE testExecption;

# 重新定义存储过程,体现错误的处理程序
DELIMITER //
CREATE PROCEDURE testExecption()
	BEGIN
		# 在开始就声明处理程序
		# 方式一:如果是使用错误名称,需要先定义条件
		# DECLARE Field_Not_Be_Null CONDITION FOR 1048;
		# DECLARE CONTINUE HANDLER FOR Field_Not_Be_Null SET @result = 'Column stu_id cannot be null';
		# 方式二:捕获sqlstate_value
		# DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @result = 'Column stu_id cannot be null';
		# 方式三:捕获MySQL_error_code
		DECLARE CONTINUE HANDLER FOR 1048 SET @result = 'Column stu_id cannot be null';
		SET @X = 1;
		UPDATE t_student set stu_id = NULL where stu_name = 'jack';
		SET @X = 2;
		UPDATE t_student set stu_id = '001' where stu_name = 'jack';
		SET @X = 3;
	END //
DELIMITER ;

# 调用存储过程
call testExecption();

# 查询变量X和result
select @X,@result;

执行结果如下
在这里插入图片描述

如有错误,欢迎指正!!!

<think>好的,我现在需要解决MySQL存储过程中出现的未声明变量错误。首先,我得弄清楚这个错误的具体原因。根据我的经验,存储过程中的变量如果未正确声明,通常会导致这样的错误。例如,变量名拼写错误或者作用域问题都可能是诱因。 我应该先检查存储过程的代码,确认所有变量都使用`DECLARE`语句声明过。比如,变量是否在`BEGIN...END`块内正确声明?如果在没有声明的情况下直接使用变量,比如`SET var = 1;`而没有之前的`DECLARE var INT;`,肯定会报错。此外,还要注意变量的作用域,特别是在嵌套的`BEGIN...END`块中,内部块声明的变量在外部是不可见的[^1]。 另外,参数变量名称冲突也可能导致问题。存储过程的参数名如果声明的变量名相同,可能会被误认为已声明,但实际上需要明确区分。比如,参数名是`input_param`,变量名也用了同样的名字,这时候就需要用不同的名称来避免冲突。 还有,用户变量局部变量的区别需要注意。用户变量以`@`开头,比如`@user_var`,而局部变量不需要。如果在存储过程中误将局部变量写成用户变量,或者反过来,也会导致未声明的错误。比如,声明了局部变量`var`却错误地使用`@var`,系统会认为这是未声明的用户变量。 检查完这些基本点之后,可能还需要查看MySQL的文档,确认变量声明的正确语法作用域规则。例如,变量声明必须放在`BEGIN`块的最开始部分,任何非声明语句(如`SET`或`SELECT`)出现在`DECLARE`之前都会导致错误[^2]。 此外,代码中的逻辑错误也可能间接引发未声明变量的问题。例如,条件分支中声明的变量在外部被引用,或者循环结构中变量的作用域不当。需要仔细检查代码结构,确保变量在使用前已经被正确声明。 如果以上步骤都检查无误,但问题仍然存在,可能需要考虑是否有拼写错误或者使用了保留关键字作为变量名。比如,变量名`count`可能MySQL的保留关键字冲突,这时候应该使用反引号包裹或者更换变量名。 最后,通过逐步注释掉部分代码,定位具体出错的位置,可以帮助更快找到问题所在。如果还是无法解决,查阅MySQL的官方文档或社区支持可能会有帮助。</think>### MySQL存储过程未声明变量错误解决方案 #### 1. 检查变量声明语法 - **必须使用`DECLARE`声明局部变量**:在存储过程的`BEGIN...END`块中,局部变量需通过`DECLARE`显式声明,且声明需放在所有执行语句之前。 ```sql CREATE PROCEDURE example() BEGIN DECLARE var INT; -- 正确声明 SET var = 1; -- 正确使用 END; ``` **错误示例**: ```sql CREATE PROCEDURE example() BEGIN SET var = 1; -- 错误:var未声明 DECLARE var INT; END; ``` #### 2. 作用域冲突排查 - **嵌套块作用域限制**:内部`BEGIN...END`块声明的变量无法在外部访问。 ```sql CREATE PROCEDURE example() BEGIN DECLARE outer_var INT; BEGIN DECLARE inner_var INT; SET outer_var = 1; -- 允许 END; SET inner_var = 2; -- 错误:inner_var未声明[^1] END; ``` #### 3. 参数变量命名冲突 - **避免参数名变量名重复**:存储过程参数局部变量名称冲突会导致变量未声明的假象。 ```sql CREATE PROCEDURE example(IN input_param INT) BEGIN DECLARE input_param INT; -- 错误:参数名冲突 SET input_param = 10; -- 实际修改的是参数而非局部变量 END; ``` #### 4. 用户变量局部变量区分 - **用户变量需以`@`开头**:局部变量(如`var`)用户变量(如`@var`)是两种不同的类型。 ```sql CREATE PROCEDURE example() BEGIN DECLARE local_var INT; SET local_var = 1; -- 正确 SET @user_var = 2; -- 正确(用户变量) SET undeclared = 3; -- 错误:未声明变量 END; ``` #### 5. 检查拼写保留字 - **避免关键字冲突**:使用保留字(如`count`)作为变量名需用反引号包裹。 ```sql CREATE PROCEDURE example() BEGIN DECLARE `count` INT; -- 正确:使用反引号 SET `count` = 10; END; ``` #### 6. 调试建议 - **分段注释法**:通过注释部分代码逐步定位错误位置。 - **SHOW ERRORS命令**:执行`SHOW ERRORS;`查看详细错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值