共计 4653 个字符,预计需要花费 12 分钟才能阅读完成。
在 MySQL/MariaDB 中有好几种变量类型:用户自定义变量、系统变量、一般的临时变量(即本地变量,或称为局部变量)。
1. 用户变量
用户变量是基于会话的,也是基于用户的,所以我觉得称之为会话变量更合适,但会话变量一般用来表示系统会话变量(后面会说明),所以还是称之为用户变量好了。
只有本用户才能引用自身的用户变量,其他用户无法引用,且当用户退出会话时,用户变量自动销毁。
用户变量使用 ”@” 开头,用户变量可以直接赋值,无需事先声明。在引用未赋值的用户变量时,该变量值为 null。
有以下三种方式设置用户变量:
1.set 语句,此时可以使用 ”=” 或者 ”:=” 操作符;
2.select 语句,此时只能使用 ”:=” 格式赋值,因为除了 set 语句中,”=” 都会被视为比较操作符。;
3.select … into var_name from TABLE 语句,此时要求 select 语句只能返回标量值,即单行数据。因此为了保险,select into var_name 的时候,应尽量结合 limit 语句限制输出。
set @a1=1,@a2=3,@a3:=2;
select @a4:=@a1+@a3;
select 33,’abc’ into @a5,@a6 from dual;
查看变量值可以使用 select 语句。
MariaDB [test]> select @a1,@a2,@a3,@a4,@a5,@a6,@a7;
+——+——+——+——+——+——+——+
| @a1 | @a2 | @a3 | @a4 | @a5 | @a6 | @a7 |
+——+——+——+——+——+——+——+
| 1 | 2 | 3 | 4 | 5 | abc | NULL |
+——+——+——+——+——+——+——+
在 mariadb 10.2.6 中,引入了一张系统架构表 information_schema.USER_VARIABLES,该表中记录了当前用户当前会话定义的用户变量信息。该信息架构表在 mysql 中没有。
MariaDB [test]> SELECT * FROM information_schema.USER_VARIABLES;
+—————+—————-+—————+——————–+
| VARIABLE_NAME | VARIABLE_VALUE | VARIABLE_TYPE | CHARACTER_SET_NAME |
+—————+—————-+—————+——————–+
| a6 | abc | VARCHAR | utf8 |
| i | 2 | INT | utf8 |
| a5 | 33 | INT | utf8 |
| a1 | 1 | INT | utf8 |
| a4 | 3 | INT | utf8 |
| a2 | 3 | INT | utf8 |
| a3 | 2 | INT | utf8 |
+—————+—————-+—————+——————–+
2. 系统变量
在 MySQL/mariadb 中维护两种系统变量:全局系统变量和会话系统变量。系统变量是用来设置 MySQL 服务运行属性和状态的。
全局系统变量使用 global 或者 ”@@global.” 关键字来设置。会话系统变量使用 session 或者 ”@@session.” 关键字来设置,其中 session 可以替换为 Local,它们是同义词。如果省略这些关键字,则默认为 session 系统变量。设置 global 系统变量要求具有 super 权限。
— 设置全局系统变量
set global sort_buffer_size=32M;
set @@global.sort_buffer_size=32M;
— 设置会话系统变量
set session sort_buffer_size=32M;
set @@session.sort_buffer_size=32M;
set sort_buffer_size=32M;
— 查看全局系统变量值
select @@global.sort_buffer_size;
show global variables like “sort_buffer%”;
— 查看会话系统变量,不能使用 select sort_buffer_size
select @@session.sort_buffer_size;
select @@sort_buffer_size;
show [session] variables like “sort_buffer%”;
— 一次性设置多个变量,包括会话变量、全局变量以及用户变量
SET @x = 1, SESSION sql_mode = ”;
SET GLOBAL sort_buffer_size = 1000000, SESSION sort_buffer_size = 1000000;
SET @@global.sort_buffer_size = 1000000, @@local.sort_buffer_size = 1000000;
SET GLOBAL max_connections = 1000, sort_buffer_size = 1000000;
全局系统变量对全局有效,当有新的会话打开时,新会话会继承全局系统变量的值,所以设置全局系统变量之后新打开的会话都会继承设置后的值。设置全局系统变量对已经打开的连接无效,但是其他已经打开的连接可以查看到设置后的全局系统变量值。
系统变量按照是否允许在运行时修改,还分为动态变量和静态变量。能在运行过程中修改的变量称为动态变量,只能在数据库实例关闭状态下修改的变量称为静态变量或只读变量。动态变量使用 set 修改。如果在数据库实例运行状态下修改静态变量,则会给出错误。如:
set @@innodb_undo_tablespaces=3;
ERROR 1238 (HY000): Variable ‘innodb_undo_tablespaces’ is a read only variable
系统变量除了可以在运行中的环境下设置,还可以在配置文件中或者 mysqld/mysqld_safe 这样的命令行中设置,甚至 mysql 客户端命令行也可以传递。在配置文件中设置系统变量时,下划线或者短横线都允许,它们表示同一个意思。例如下面的两行配置是等价的:
innodb_file_per_table=1
innodb-file-per-table=1
3. 局部变量
局部变量也称为本地变量,只能在 begin…and 语句块中生效。它不像用户变量,本地变量必须使用 declare 事先声明,所以 declare 也必须在 begin…end 中使用。
局部变量无论是声明还是调用的时候都不需要任何多余的符号(即不需要 @符号),直接使用其名称 var_name 即可。
使用 declare 声明变量,可以一次性声明多个同类型的变量,需要时可有直接为其指定默认值,不指定时默认为 null。
decalre var_name,… type [default value];
使用 set 为变量赋值。MySQL/mariadb 中 set 支持一次性赋值多个变量。
在 begin…end 中的 set 是一般 set 语句的扩展版本,它既可以设置系统变量、用户变量,也可以设置此处的本地变量。
set var_name=expr,[var_name=expr1,…]
或者使用 select…into 语句从表中获取值来赋值给变量,但是这样的赋值行为要求表的返回结果必须是单列且单行的标量结果。例如下面的语句将 col 的列值赋值给 var_name 变量。
select col into var_name from table_name;
因为局部变量只能在 begin…end 中使用,所以此处使用存储过程的例子来演示。
DROP PROCEDURE IF EXISTS haha;
DELIMITER $$
CREATE PROCEDURE haha()
BEGIN
DECLARE a INT;
SET a=1;
SET @i:=2;
SELECT a,@i;
END$$
DELIMITER ;
CALL haha();
a @i
—— ——–
1 2
在 MySQL 中,begin…end 只能定义在存储程序中,所以 declare 也只能定义在存储程序内。但在 mariadb 中,begin…end 是允许定义在存储程序 (存储函数,存储过程,触发器,事件) 之外的,所以 decalre 也算是能够定义在存储程序之外吧。需要定义在存储程序之外时,使用 begin not atomic 关键字即可。例如:
delimiter $$
begin not atomic
declare a int;
set a=3;
select a;
end$$
3.1 declare 锚定其他对象的数据类型
在 mariadb 10.3 中(注意版本号,目前 10.3 版本还在测试中),declare 语句允许在存储程序中使用 TYPE OF 和 ROW TYPE OF 关键字基于表或游标来锚定数据类型。在 mysql 中不支持数据类型的锚定功能。
例如:
DECLARE tmp TYPE OF t1.a; — 基于表 t1 中的 a 列获取数据类型
DECLARE rec1 ROW TYPE OF t1; — 锚定表 t1 中行数据类型
DECLARE rec2 ROW TYPE OF cur1; — 基于游标 cur1 获取行数据类型
通过其他对象来锚定本地变量的数据类型时,如果对象的数据类型改变,则本地数据类型也随之改变。这在某些时候非常有利于维护存储程序。
在定义存储程序时,不会检查 declare 锚定的对象是否存在。但在调用存储程序时,会先检查锚定对象是否存在。
当 declare 语句的锚定是基于表对象 (不是游标) 时,在调用存储程序的瞬间就会检查锚定的表是否存在,然后立刻声明该变量。因此:
- (1). 带有锚定功能的 decalre 语句可以定义在存储程序的任意位置;
- (2). 在存储程序中删除锚定的表对象,或者修改了锚定的表结构,都不会改变存储程序调用时声明的变量类型;
- (3). 所有带锚定功能的 declare 都是在存储程序调用之初被赋值的。
当 declare 语句的锚定是基于游标对象时,变量的数据类型是在执行变量声明语句时才获取到的。数据类型仅只锚定一次,之后不再改变。如果游标中的 ROW TYPE OF 变量是定义在一个循环之中,则数据类型在循环的开头就已经获取,且之后的循环不再改变。
示例:
create table t1(a int,b char(20));
drop procedure if exists haha;
delimiter $$
create procedure haha()
begin
declare x type of t1.a;
set x=1;
select x;
end$$
delimiter ;
call haha();