上一篇介绍了 MySQL 的内存管理和磁盘管理,这一篇将介绍存储过程和触发器相关的内容。
存储过程是一组为了完成特定功能的 SQL 语句集合,使用存储过程的目的在于:将常用且复杂的 SQL 语句预先写好,然后用一个指定名称存储起来,这个过程经过编译解析、执行优化后存储在数据库中,当以后需要使用这个过程时,只需调用根据名称调用即可。
优点:
缺点:
存储过程难以维护,同时扩展性和移植性都很差,所以一般都不会使用。但是在以下场景中可以使用存储过程:
DELIMITER $
-- 创建的语法:指定名称、入参、出参
CREATE
PROCEDURE 存储过程名称(返回类型 参数名1 参数类型1, ....)
[ ...约束条件... ]
-- 表示开始编写存储过程体
BEGIN
-- 具体组成存储过程的SQL语句....
-- 表示到这里为止,存储过程结束
END $
DELIMITER ;
DELIMITER $
表示指定结束标识。在 MySQL 中默认是以分号 ;
作为一条语句的结束标识,因此当存储过程的过程体中,如果包含了 SQL 语句,且以分号结束时, 会认为存储过程的定义也结束了,过程体就会和结束符冲突,所以一般要重新定义结束符,例如DELIMITER $
,表示以 $
作为结束标识,只有当识别到 $
符时,才会认为结束了。所以在结束后,需要再次把结束符改回分号,即 DELIMITER ;
。
存储过程支持四种类型,主要依赖于 IN、OUT、INOUT 三个关键字来区分:
NOT
表示为固定的,默认为非固定的。示例:
DELIMITER $
CREATE
-- 在定义存储过程时,用 OUT 声明了一个返回值
PROCEDURE get_user_id(INOUT parameters varchar(255))
BEGIN
select `user_id` into parameters from `zz_users` where `user_name` = parameters;
END $
DELIMITER ;
系统变量是系统定义的,在 MySQL 中全局生效,也可以通过 session 关键字,表示只对当前连接生效。
对于系统变量,想要查看或修改,使用两个 @@
符号即可,例如:
-- 查看某个系统变量
select @@xxx;
-- 修改某个系统变量
set @@xxx = "xxx";
用户自定义的变量,想要查看或修改,使用一个 @
符号即可,例如:
set @变量名称 = 变量值;
select @变量名称;
用户变量的赋值,中间的 =
也可改为 :=
,其作用也是相同的。除此之外,用户变量的定义还可以和 SQL 组合,如下:
-- 将用户表的总行数赋值给 row_count 变量
select @row_count := count(*) from `zz_users`;
-- 将 user_id 的平均值赋给 avg_user_id 变量
select avg(user_id) into @avg_user_id from `zz_users`;
局部变量的有效范围只是当前存储过程,定义方式如下:
DECLARE 变量名称 数据类型 default 默认值;
DECLARE message varchar(255) default "not message";
-- 赋值方式一
SET message = 变量值;
SET message := 变量值;
-- 赋值方式二
select 字段名或函数 into message from 表名;
对于局部变量的定义,必须要写在 BEGIN、END 之间,否则会提示语法错误。
IF 条件判断 THEN
-- 分支操作.....
ELSEIF 条件判断 THWN
-- 分支操作.....
ELSE
-- 分支操作.....
END IF
-- 第一种语法
CASE 变量
WHEN 值1 THEN
-- 分支操作1....
WHEN 值2 THEN
-- 分支操作2....
.....
ELSE
-- 分支操作n....
END CASE;
在存储过程中可以给每个循环取一个名字,如果想要跳出一个循环,需要结合 LEAVE 这个关键字,否则会令循环成为一个死循环。
循环名称:LOOP
-- 循环体....
END LOOP 循环名称;
【循环名称】:WHILE 循环条件 DO
-- 循环体....
END WHILE 【循环名称】;
【循环名称】:REPEAT
-- 循环体....
UNTIL 结束循环的条件判断
END REPEAT 【循环名称】;
LEAVE、ITERATE 两个跳转的关键字,就相当于 break 和 continue。
-- 跳出某个循环
LEAVE 循环名称;
-- 跳过某次循环
ITERATE 循环名称;
游标可以对一个结果集中的数据按条处理,也就意味着原本查询出的数据是一个整体性质的集合,而使用游标可以对该集合中的数据逐条处理,在使用游标时一般都会遵循下述四步:
-- ①声明(创建)游标
DECLARE 游标名称 CURSOR FOR select ...;
-- ②打开游标
OPEN 游标名称;
-- ③使用游标
FETCH 游标名称 INTO 变量名称;
-- ④关闭游标
CLOSE 游标名称;
示例:
DELIMITER $
CREATE
PROCEDURE id_odd_number_sum(IN N int(8), OUT sum int(8))
BEGIN
-- 声明局部变量:
-- uid:用于记录每一个user_id
-- odd_id_count:记录奇数ID的个数
-- odd_id_sum:记录奇数ID的和
DECLARE uid int(8) DEFAULT 0;
DECLARE odd_id_count int(8) DEFAULT 0;
DECLARE odd_id_sum int(8) DEFAULT 0;
-- 声明一个游标:存储倒序的user_id结果集
DECLARE uid_cursor CURSOR FOR select user_id from zz_users order by user_id desc;
-- 打开游标
OPEN uid_cursor;
-- 使用游标
REPEAT
-- 将游标中的每一条user_id值,赋给user_id变量
FETCH uid_cursor INTO uid;
-- 如果当前user_id是奇数,则将ID值累加到sum中
IF uid % 2 != 0 THEN
SET odd_id_count = odd_id_count + 1;
SET odd_id_sum = odd_id_sum + uid;
END IF;
-- 根据传入的N来决定循环的次数
UNTIL odd_id_count >= N END REPEAT;
-- 将前N个奇数ID之和赋给外部变量:sum
SET sum = odd_id_sum;
-- 关闭游标
CLOSE uid_cursor;
END $
DELIMITER ;
在 MySQL 中也提供了一系列命令,来完成存储过程的查看、修改和删除,如下:
SHOW PROCEDURE STATUS;
:查看当前数据库中的所有存储过程。SHOW PROCEDURE STATUS WHERE db = '库名' AND NAME = '过程名';
:查看指定库中的某个存储过程。SHOW CREATE PROCEDURE 存储过程名;
:查看某个存储过程的源码。ALTER PROCEDURE 存储过程名称 ....
:修改某个存储过程的特性。DROP PROCEDURE 存储过程名;
:删除某个存储过程。也可以通过以下命令来查看某张表的存储过程:
-- 查看某张表的所有存储过程
select * from 表名.Routines where routine_type = "PROCEDURE";
-- 查看某张表的某个存储过程
select * from 表名.Routines where routine_name = "过程名" AND routine_type = "PROCEDURE";
触发器本质上是一种特殊的存储过程,存储过程需要人为手动调用,而触发器则不需要,它可以在执行某项数据操作后自动触发。
对于每一个触发器而言,总共有插入、修改、删除三种触发事件可选,同时也可以选择将触发器放在事件开始前或结束后执行。另外,创建触发器时必须要指定表名。创建语法如下:
CREATE TRIGGER 触发器名称
{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON 表名
FOR EACH ROW
-- 触发器的逻辑(代码块);
使用示例:
DELIMITER $
CREATE TRIGGER zz_users_insert_before
BEFORE INSERT ON zz_users
FOR EACH ROW
BEGIN
insert into `register_log` values(NOW(),"北京市海淀区","IOS");
END $
DELIMITER ;
在触发器中,NEW 表示新数据,OLD 表示老数据,各类型的事件如下:
使用示例:
DELIMITER $
CREATE TRIGGER zz_users_update_before
BEFORE UPDATE ON zz_users
FOR EACH ROW
BEGIN
DECLARE new_name varchar(255);
DECLARE old_name varchar(255);
-- 可以通过 NEW 关键字拿到修改后的新数据(粉熊)
SET new_name := NEW.user_name;
-- 可以通过 OLD 关键字拿到修改前的老数据(棕熊)
SET old_name := OLD.user_name;
END $
DELIMITER ;
触发器的管理命令如下:
SHOW TRIGGERS;
:查看当前数据库中定义的所有触发器。SHOW CREATE TRIGGER 触发器名称;
:查看当前库中指定名称的触发器。SELECT * FROM information_schema.TRIGGERS;
:查看MySQL
所有已定义的触发器。DROP TRIGGER IF EXISTS 触发器名称;
:删除某个指定的触发器。本文介绍了 MySQL 存储过程和触发器。
下一节将介绍 MySQL 的表分区和分库分表。