在MySQL/MariaDB中有好幾種變量類型:用戶自定義變量、系統變量、通常的臨時變量(即本地變量,或稱爲局部變量)。mysql
用戶變量是基於會話的,也是基於用戶的,因此我以爲稱之爲會話變量更合適,但會話變量通常用來表示系統會話變量(後面會說明),因此仍是稱之爲用戶變量好了。sql
只有本用戶才能引用自身的用戶變量,其餘用戶沒法引用,且當用戶退出會話時,用戶變量自動銷燬。數據庫
用戶變量使用"@"開頭,用戶變量能夠直接賦值,無需事先聲明。在引用未賦值的用戶變量時,該變量值爲null。session
有如下三種方式設置用戶變量:架構
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 | 3 | 2 | 3 | 33 | 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 |
+---------------+----------------+---------------+--------------------+
在MySQL/mariadb中維護兩種系統變量:全局系統變量和會話系統變量。系統變量是用來設置MySQL服務運行屬性和狀態的。ui
全局系統變量使用global或者"@@global."關鍵字來設置。會話系統變量使用session或者"@@session."關鍵字來設置,其中session能夠替換爲Local,它們是同義詞。若是省略這些關鍵字,則默認爲session系統變量。設置global系統變量要求具備super權限。atom
-- 設置全局系統變量
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;
全局系統變量對全局有效,當有新的會話打開時,新會話會繼承全局系統變量的值,因此設置全局系統變量以後新打開的會話都會繼承設置後的值。設置全局系統變量對已經打開的鏈接無效,可是其餘已經打開的鏈接能夠查看到設置後的全局系統變量值。spa
系統變量按照是否容許在運行時修改,還分爲動態變量和靜態變量。能在運行過程當中修改的變量稱爲動態變量,只能在數據庫實例關閉狀態下修改的變量稱爲靜態變量或只讀變量。動態變量使用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
局部變量也稱爲本地變量,只能在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$$
在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語句的錨定是基於表對象(不是遊標)時,在調用存儲程序的瞬間就會檢查錨定的表是否存在,而後馬上聲明該變量。所以:
當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();