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用户自定义变量:使用详解及其使用场景案例