变量与作用域
1.变量的分类
MySQL中的变量是容易让人混淆的部分
- MySQL本身的变量分为系统变量和自定义变量(用户变量)
- 系统变量主要是影响MySQL服务器运行的配置,又分为全局变量和会话(连接)变量,当MySQL启动时,会从配置文件读取系统变量到全局变量,当一个连接建立时,会从全局变量复制到会话变量
- 自定义变量(用户变量)都是会话变量,生效于每次连接内
- 在存储过程中又专门有存储过程变量,是需要声明使用的
在存储过程中我们使用的主要是存储过程变量和用户变量,极少数的情况可能需要去更改一下系统配置的会话变量
2.存储过程变量
存储过程变量需要声明,作用域是一个begin ... end代码块中
BEGIN
declare v_student_name varchar(255) default 'Tony';
END
存储过程变量是正统的变量使用方式,有明确可控的作用域,有准确声明的类型,推荐在存储过程中使用。
BEGIN
declare v_student_name varchar(255) default 'Tony';
BEGIN
declare v_teacher_name varchar(255);
END;
select v_teacher_name; #ERROE! 这里不能访问teacher_name
END
声明变量的类型的时候请根据需要选择合适的类型,注意大小精度限制
存储过程变量可以使用default初始化默认值,没有初始化的就是null
声明的变量都以v_开头,传入的变量都以p_开头,表里的字段不带前缀,这是我们的内部规定,对于阅读者友好,而且也不容易写错,是一种约定优于配置的体现
3.用户变量
用户变量是以@开头的自定义变量,作用域是当前会话(连接)
用户变量无需声明,直接赋值使用即可,而且不严格区分类型,可以混用
set @temp = 'abc';
set @temp = 123;
一般只有临时用一下的变量才会用到用户变量,由于该变量在会话内都不会被自动销毁,存储过程运行完后还存在,因此最好最好不要用,一不小心就掉坑里
4.更改MySQL配置的会话变量
有时候可能不确定MySQL的一些配置是否满足运行条件,可以在会话内更改一下配置的会话变量
set @@max_sp_recursion_depth = 255;
5.变量的赋值
变量的赋值主要有set, select into 两种方式
有表teacher_table
| teacher_id | name | age |
|---|---|---|
| 1 | Jessy | 25 |
| 2 | Mark | 40 |
BEGIN
declare v_student_name varchar(255);
declare v_teacher_name varchar(255);
declare v_teacher_age int;
set v_student_name = 'Tony';
select name, age into v_teacher_name, v_teacher_age
from teacher_table where teacher_id = 1 limit 1;
END
上述代码中声明了两个变量,没有初始化赋值因此声明后它们都是null
使用set赋值一般是等号右侧能明确写出来值的情况,当数据需要从表里面取出来赋值的情况下,就需要用select into来赋值了
由于赋值必须显式的使用set或者select into, 因此存储过程中不需要使用两个等号来表示相等
需要注意的是select into的时候不能出多行结果,只能有一行或者没有结果,不然运行时会报错,加上limit 1以防万一
如果这里没有select出结果,那么v_teacher_name还是之前的值,也就是null
6.严格模式
MySQL的配置sql_mode中有个选项是严格模式STRICT_TRANS_TABLES,在严格模式下不同类型的赋值会报错
BEGIN
declare v_student_id int;
declare v_student_age int;
set v_student_id = 'abc' #报错!
select age into v_student_age
from student_table where student_id = 1 limit 1;
END
理论上应该开启严格模式以便防止错误的赋值,但实际上有些错误是运行的时候才会报出来的。例如上面示例中对于v_student_age的赋值,如果age字段是个null,那运行的时候这里就崩了,这些在写代码的时候是很难防范的,因此我们在实际使用的过程中是不开严格模式的。后文的示例都是在不开严格模式的情况下运行的