1、到底MySQL的變量分哪幾類?
MySQL變量一共分爲兩大類:用戶自定義變量和系統變量。以下:php
- 用戶自定義變量
- 局部變量
- 會話變量
- 系統變量
- 會話變量
- 全局變量
本文涉及的內容爲用戶自定義會話變量,若對其餘分類無感,請點擊這裏。html
PS:用戶定義的會話變量和系統定義的會話變量有什麼區別?mysql
局部變量
局部變量通常用於SQL的語句塊中,好比存儲過程當中的begin和end語句塊。其做用域僅限於該語句塊內。生命週期也僅限於該存儲過程的調用期間。sql
1
2
3
4
5
6
7
8
9
10
11
|
drop
procedure
if exists
add
;
create
procedure
add
(
in
a
int
,
in
b
int
)
begin
declare
c
int
default
0;
set
c = a + b;
select
c
as
c;
end
;
|
上述存儲過程當中定義的變量c就是局部變量。服務器
會話變量
會話變量即爲服務器爲每一個客戶端鏈接維護的變量。在客戶端鏈接時,使用相應全局變量的當前值對客戶端的回話變量進行初始化。設置會話變量不須要特殊權限,但客戶端只能更改本身的會話變量。其做用域與生命週期均限於當前客戶端鏈接。session
會話變量的賦值:函數
1
2
3
|
set
session var_name = value;
set
@@session.var_name = value;
set
var_name = value;
|
會話變量的查詢:單元測試
1
2
3
|
select
@@var_name;
select
@@session.var_name;
show session variables
like
"%var%"
;
|
全局變量
全局變量影響服務器總體操做。當服務器啓動時,它將全部全局變量初始化爲默認值。這些默認值能夠在選項文件中或在命令行中指定的選項進行更改。要想更改全局變量,必須具備SUPER權限。全局變量做用於server的整個生命週期,可是不能跨重啓。即重啓後全部設置的全局變量均失效。要想讓全局變量重啓後繼續生效,須要更改相應的配置文件。學習
全局變量的設置:測試
1
2
|
set
global
var_name = value; //注意:此處的
global
不能省略。根據手冊,
set
命令設置變量時若不指定
GLOBAL
、SESSION或者
LOCAL
,默認使用SESSION
set
@@
global
.var_name = value; //同上
|
全局變量的查詢:
1
2
|
select
@@
global
.var_name;
show
global
variables
like
"%var%"
;
|
2、MySQL用戶自定義變量詳解
你能夠利用SQL語句將值存儲在用戶自定義變量中,而後再利用另外一條SQL語句來查詢用戶自定義變量。這樣以來,能夠再不一樣的SQL間傳遞值。
用戶自定義變量的聲明方法形如:@var_name,其中變量名稱由字母、數字、「.」、「_」和「$」組成。固然,在以字符串或者標識符引用時也能夠包含其餘字符(例如:@'my-var',@"my-var",或者@`my-var`)。
用戶自定義變量是會話級別的變量。其變量的做用域僅限於聲明其的客戶端連接。當這個客戶端斷開時,其全部的會話變量將會被釋放。
用戶自定義變量是不區分大小寫的。
使用SET語句來聲明用戶自定義變量:
1
|
SET
@var_name = expr[, @var_name = expr] ...
|
在使用SET設置變量時,可使用「=」或者「:=」操做符進行賦值。
固然,除了SET語句還有其餘賦值的方式。好比下面這個例子,可是賦值操做符只能使用「:=」。由於「=」操做符將會被認爲是比較操做符。
mysql> SET @t1=1, @t2=2, @t3:=4; mysql> SELECT @t1, @t2, @t3, @t4 := @t1+@t2+@t3; +------+------+------+--------------------+ | @t1 | @t2 | @t3 | @t4 := @t1+@t2+@t3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+
用戶變量的類型僅限於:整形、浮點型、二進制與非二進制串和NULL。在賦值浮點數時,系統不會保留精度。其餘類型的值將會被轉成相應的上述類型。好比:一個包含時間或者空間數據類型(temporal or spatial data type)的值將會轉換成一個二進制串。
若是用戶自定義變量的值以結果集形式返回,系統會將其轉換成字符串形式。
若是查詢一個沒有初始化的變量,將會以字符串類型返回NULL。
不要在同一個非SET語句中同時賦值並使用同一個用戶自定義變量
用戶自定義變量能夠用於不少上下文中。可是目前並不包括那些顯式使用常量的表達式中,好比SELECT中的LIMIT子句,或者LOAD DATA中的IGNORE N LINES的字句中。
一般來講,除了在SET語句中,不要再同一個SQL語句中同時賦值並使用同一個用戶自定義變量。舉個變量自增的例子,下面的是沒問題的:
1
|
SET
@a = @a + 1;
|
對於其餘語句,好比SELECT,也許會獲得指望的效果,但這真心不靠譜。好比下面的語句,也許你天然地會認爲MySQL會先執行@a的值,而後再進行賦值操做:
1
|
SELECT
@a, @a:=@a+1, ...;
|
然而,用戶自定義變量表達式的計算順序尚未定義呢。
除此以外,還有另外一個問題。變量的默認返回類型由語句開始時的類型決定的,正以下面的例子:
1
2
|
mysql>
SET
@a=
'test'
;
mysql>
SELECT
@a,(@a:=20)
FROM
tbl_name;
|
上述的SELECT語句中,MySQL會報告給客戶端第一列的字段類型爲字符串,同時將全部對@a變量的使用均轉換爲字符串處理,儘管在SELECT語句中將@a變量設置爲數字類型。在SELECT語句執行後,@a變量纔會在下一個語句中識別爲數字類型。
爲了不上述問題的發生,要麼不在同一個語句中同時賦值並使用變量,要麼在使用以前,將變量設置爲0,0.0,或者'',以肯定它的數據類型。
變量的值是在SQL發送到客戶端後才計算的
在SELECT語句中,在每個select表達式被髮送給客戶端後,纔會進行計算。這就意味着,在形如HAVING,GROUP BY和ORDER BY只句中有使用在當前select表達式定義的變量的狀況下,該語句將不會獲得如期的效果。
1
|
mysql>
SELECT
(@aa:=id)
AS
a, (@aa+3)
AS
b
FROM
tbl_name
HAVING
b=5;
|
上述在HAVING只句中使用了在當前的select列表中定義的別名b,其使用了變量@aa。這條語句並不會獲得如期的效果:@aa變量爲上一次SQL語句執行的結果集中的ID值,並不是當前的。
3、MySQL用戶自定義變量的實際應用舉例
項目
超級話題積分系統
術語
積分行爲:如轉發、評論超級話題下的帖子、簽到某超級話題或者帖子被其餘人回覆等行爲。
積分行爲次數:產生積分行爲的累計次數。
業務場景
用戶在某超級話題下,第N次產生累計積分的行爲,如轉發微博,會增長該用戶在該超級話題下的積分總數。具體的積分規則見長文章。
問題
曾有用戶反饋說超級話題積分有漏記的狀況:爲何我評論了卻沒有加分;爲何轉發了超級話題帖子沒有加分等等。隨後,咱們當即經過查詢後臺的積分記錄發現,會看到轉發行爲在第5次時,積分的增長卻爲0。這顯然是不正常的。
首先,排除了根據積分行爲的次數來計算積分值的問題。好比第5次轉發微博應增長6分。這塊的規則,利用二分法寫死在程序裏面,也作過單元測試,不會有問題。那麼,問題就鎖定在這個積分行爲的次數。
首先來看看積分次數的獲取:
1
2
3
4
|
public
static
function
find(
$uid
,
$aid
,
$status
) {
$sql
=
'SELECT * FROM '
.self::table(
$aid
).
' WHERE uid = ? AND aid = ? AND status = ?'
;
return
Comm_Db::d(Comm_Db::DB_BASIC)->fetchRow(
$sql
,
array
(
$uid
,
$aid
,
$status
));
}
|
而後,利用上述find()方法來取得該用戶在某超級話題下的某積分行爲的累計次數。這是有問題的,在於讀於從庫,但並不保證從庫的值是最新的,因此致使當前獲取的積分行爲次數並不必定是正確的(小於等於實際的值)。
隨後,程序會根據當前的次數計算積分值,並分別更新積分值和該行爲的積分行爲次數值。
因此,此次利用MySQL的用戶自定義會話變量的方式,來解決上述問題。
1
2
3
4
5
6
7
8
|
public
static
function
incCounter(
$uid
,
$aid
,
$status
) {
$db
= Comm_Db::d(Comm_Db::DB_BASIC);
$sql
=
"UPDATE "
. self::table(
$aid
) .
" SET `ctn_counter`=@ctn_counter:=`ctn_counter`+1 WHERE `uid` = ? AND `aid` = ? AND `status` = ?"
;
$db
->execute(
$sql
,
array
(
$uid
,
$aid
,
$status
));
$sql
=
"SELECT @ctn_counter"
;
$rs
=
$db
->fetchOne(
$sql
, null, true);
return
$rs
;
}
|
改進後,如上述函數,程序將先進行調用incCounter()函數,將當前的積分行爲次數自增,並將值存入當前變量中。隨後,當即將其讀取並返回給PHP進行積分處理。這樣一來,就保證了積分行爲次數的正確性。
4、關於MySQL用戶自定義變量的結束語
在此次的「填坑」過程當中,使用了MySQL變量解決了MySQL主從服務同步延遲的問題。這篇文章也算是對於MySQL用戶自定義變量深刻學習的記載。
除此以外,仍有個問題,用戶自定義的會話變量是存在進程內存中的。可是,是存在客戶端進程中仍是服務端進程中的呢?
參考文章:
- https://my.oschina.net/guanyue/blog/211706
- http://dev.mysql.com/doc/refman/5.6/en/user-variables.html
- http://www.uuboku.com/392.html
文章來源:胡旭博客 => 深刻MySQL用戶自定義變量:使用詳解及其使用場景案例