mysql中的事件、存储过程、触发器

目录
事件event 1
存储过程PROCEDURE 2
触发器 6
相关SHOW命令 7
示例 7




本篇涉及的SQL语句有:

CREATE EVENT、CREATE PROCEDURE、CREATE TRIGGER 

介绍了mysql中的事件event、存储过程procedure、触发器trigger,并给出具体例子


事件event

事件调度器是在MySQL5.1中新增的功能,可以作为定时任务调度器,取代部分原来只有操作系统任务调度器才能完成的定时功能。例如Linux中的crontab只能精确到每分钟执行一次,而MySQL事件调度器可以实现每秒钟执行一个任务,这些对实时性要求较高的环境来说是非常实用的。
事件触发器可以设置每隔一定时间执行指定的任务。事件由一个特定的线程来管理,即“事件调度器”,通过event_scheduler变量可以动态地控制mysql事件调度器,如果启用了,则可以使用SHOW PROCESSLIST查看事件调度器的线程。


语法:

create event [ if not exists] event_name
on schedule schedule_type        #  任务执行的时间 或 间隔
[on completion [not] preserver]     #  指定事件过期后,是否仍然保存,而不是被删除
[comment ‘comment’]            #  event的注释
DO event_body;                 #  event具体做什么,可以是SQL语句 
schedule_type:
   AT timestamp [+ INTERVAL interval] …
   | EVERY interval
    [ STARTS timestamp [+ INTERVAL interval] …]
    [ENDS timestamp [+ INTERVAL interval] …]
interval:
  quantity { YEAR | QUARTER | MONTH | DAY | HOUR| MNUTE | WEEK | SECOND | 
YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND |

HOUR_MINUTE |  HOUR_SECOND | MINUTE_SECOND}


例子:每五分钟调度一次p_up_t1存储过程
mysql> create event if not exists e_5minute
-> on schedule every 5 minute
->on completion preserver
    -> comment 'this e will call procedure p_up_t1'
    -> do call p_up_t1(@id);

Query OK, 0 rows affected (0.00 sec) 


注意:
只有在my.cnf中[mysqld]下面指定 event_scheduler=1启动mysql事件调度器,或者在mysql中通过set global event_scheduler=on动态启动事件调度器,或 通过start mysql –event_scheduler=1启动mysql服务,才可以使用事件调度器,这时在mysql中使用show processlist可以查看事件调度器线程信息。 
创建事件需要拥有对事件所属模式的 EVENT权限。


存储过程PROCEDURE
语法:
  CREATE PROCEDURE procedure_name ( [ proc_parameter[,…] ])
  [characteristic …] routine_body; 
proc_parameter:
  [ IN | OUT | INOUT] param_name type
type:
  ane valid MySQL data type
characteristic:
   COMMENT ‘string’
| LANGUAGE SQL
| [NOT] DETERMINISTIC
 | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
 | SQL SECURITY { DEFINER | INVOKER }
routine_body:
  valid SQL routine statement 
存储过程是一组为了完成特定功能的SQL语句,经过编译后存储在数据库中。通过调用指定的存储过程名并给出参数来调用它。存储过程中可以包含逻辑控制语句和数据操作语句,可以接受参数、输出参数。
创建存储过程时需要指定参数,如果没有参数也要加上括号 procedure_name()
存储过程的三种参数类型in、out、inout
# in: 传值给存储过程,存储过程会改变这个值,改变后的变量值对于调用者是不可见的。
如set @id=10,调用procedure,执行id=id+1,call procedure返回id=11,而使用select @id,id仍为10
# out:把存储过程的值传递给调用者。在procedure内部out的被初始值为NULL,procedure返回结果时,out的值对于调用者是可见的。
使用set @id=10,调用out参数的procedure,id会被初始化为NULL,(此时id=NULL),然后返回procedure处理后的id值。使用select @id显示的是procedure处理后的id值。
# inout:由调用者对变量进行初始化,值可以被procedure改变,改变后的值对于调用者是可见的。
如set @id=10,调用procedure,返回改变的id=11,使用select @id显示也是id=11。 

示例 in , out ,inout


#in 
mysql> create procedure p_test1( in id int)
    -> begin
    -> if (id is not null) then
    -> set id = id + 1;
    -> end if;
    -> select id as id_inner;
    -> end $
Query OK, 0 rows affected (0.00 sec) 
mysql> set @id=5$
Query OK, 0 rows affected (0.00 sec) 
mysql> call p_test1(@id)$
+----------+
| id_inner |
+----------+
|        6 |
+----------+
1 row in set (0.00 sec) 
Query OK, 0 rows affected (0.00 sec) 
mysql> select @id$
+------+
| @id  |
+------+
|    5 |
+------+
1 row in set (0.00 sec)
mysql> 
#变量@id传入procedure内的值为5,执行procedure后,在procedure内部id=6,但外部变量值仍为id=5
#out
mysql> create procedure p_test2
    -> (out id int(3))
    -> begin
    ->  select id as id_inner_1;
    ->  if (id is not null) then
    ->    set id = id + 1;
    ->    select id as id_inner_2;
    ->  else
    ->    select 10 into id;
    ->  end if;
    ->  select id as id_inner_3;
    -> end$
Query OK, 0 rows affected (0.00 sec) 
#在procedure内部,out的初始值为NULL
mysql> call p_test2(@id)$
+------------+
| id_inner_1 |
+------------+
|       NULL |
+------------+
1 row in set (0.01 sec) 
+------------+
| id_inner_3 |
+------------+
|         10 |
+------------+
1 row in set (0.01 sec) 
Query OK, 0 rows affected (0.01 sec) 
#设置id的值为20
mysql> set @id=20$
Query OK, 0 rows affected (0.00 sec)
mysql> select @id$
+------+
| @id  |
+------+
|   20 |
+------+
1 row in set (0.00 sec) 
#调用p_test2,此时已经设置id的值为20
mysql> call p_test2(@id)$
+------------+
| id_inner_1 |
+------------+
|       NULL |
+------------+
1 row in set (0.00 sec) 
+------------+
| id_inner_3 |
+------------+
|         10 |
+------------+
1 row in set (0.00 sec) 
Query OK, 0 rows affected (0.00 sec)
#设置的id=20没有使用,也可以说调用p_test2时,p_test2重新初始化id为NULL,然后设置为10
mysql> select @id as id_out$
+--------+
| id_out |
+--------+
|     10 |
+--------+
1 row in set (0.00 sec) 
mysql> call p_test1(@id)$
+----------+
| id_inner |
+----------+
|       11 |
+----------+
1 row in set (0.00 sec) 
mysql> select @id as id$
+------+
| id   |
+------+
|   10 |
+------+
1 row in set (0.00 sec) 
#inout参数类型
mysql> create procedure p_test3
    -> (inout id int(3))
    -> begin
    ->   select id as id_inner_1;
    ->   if (id is not null) then
    ->     set id = id + 1;
    ->     select id as id_inner_2;
    ->   else
    ->     select 10 into id;
    ->   end if;
    ->   select id as id_inner_3;
    -> end$
Query OK, 0 rows affected (0.00 sec) 
#设置id=NULL
mysql> set @id=NULl$
Query OK, 0 rows affected (0.00 sec) 
mysql> call p_test3(@id)$
+------------+
| id_inner_1 |
+------------+
|       NULL |
+------------+
1 row in set (0.00 sec) 
+------------+
| id_inner_3 |
+------------+
|         10 |
+------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec) 
#此时id=10,继续调用p_test3
mysql> call p_test3(@id)$
+------------+
| id_inner_1 |
+------------+
|         10 |
+------------+
1 row in set (0.00 sec) 
+------------+
| id_inner_2 |
+------------+
|         11 |
+------------+
1 row in set (0.00 sec) 
+------------+
| id_inner_3 |
+------------+
|         11 |
+------------+
1 row in set (0.00 sec) 
Query OK, 0 rows affected (0.00 sec) 

mysql>



触发器
触发器是一种特殊的存储过程。当对某个表执行特定的操作时,触发器会被自动触发,执行在触发器中编译好的相关操作。而存储过程和函数,需要主动调用才会被执行。
语法:
   CREATE TRIGGER trigger_name
   trigger_time trigger_event
   ON table_name
   FOR EACH ROW
   trigger_body;
trigger_name:
   指定应用触发器的表,只能是永久表,不可以是临时表或视图。
trigger_time:
   BEFORE, AFTER 指定触发事件在行改变之前还是之后执行。
trigger_event:
   INSERT,当插入新纪录是触发,如insert, load data, replace语句
   UPDATE, 当行被更新时触发。
   DELETE,表中的行被删除时触发。如delete和replace语句,而drop和truncate不会。
trigger_body:
   触发器被激活时执行的语句操作。
    
在同一个表上不能创建具有相同触发时间和触发事件的触发器,如在表a上不能有两个BEFORE UPDATE触发器。但是可以有一个BEFORE UPDATE和一个AFTER UPDATE触发器。
在触发器中可以使用OLD和NEW引用相关表中的列。
OLD.col_name引用在update或delete之前存在的列,列是只读的,不能更改;
NEW.col_name引用在update或insert之后存在的列,可以对其进行更改。
在BEFORE触发器中,AUTO_INCREMENT列的NEW值为0,不是实际插入新纪录时将自动生成的序列号。
创建触发器的用户需要拥有TRIGGER权限,在mysql库的host, user, db, tables_priv表中设置。
当在触发器中使用OLD.col_name或NEW.col_name时,需要拥有相关表上的SELECT权限;
当在触发器中使用SET NEW.col_name = value操作时,需要拥有相关表上的UPDATE权限;
如果在存储过程中对一个表执行了insert操作,就不能同时在触发器中对这个表执行与INSERT相关的操作。否则会提示与存储过程/函数相关的错误。


相关SHOW命令

SHOW CREATE EVENT event_name;
SHOW CREATE PROCEDURE procedure_name;
SHOW CREATE TRIGGER trigger_name;
SHOW CREATE TABLE table_name;
SHOW EVENTS;
SHOW PROCEDURE STATUS [like_or_where];
SHOW TABLE STATUS [FROM db_name] [like_or_where];
SHOW TRIGGERS [FROM db_name] [like_or_where];


示例

每5分钟调度一次事件,执行存储过程对表进行插入操作,同时触发触发器对此表进行备份。
启动mysql事件调度器
#在my.cnf的[mysqld]下添加,event_scheduler=1
mysql> use db_test;
Database changed
#创建事件e_5minute
#每5分钟调用一次存储过程p_up_t1
mysql> show events;
Empty set (0.00 sec)
mysql> create event if not exists e_5minute
    -> on schedule every 5 minute
    -> comment 'this e will call procedure p_up_t1'
    -> do call p_up_t1(@id);
Query OK, 0 rows affected (0.00 sec)
#建表t_t1,t_t2
#t_t2表是t_t1的备份表,对表t_t1的insert、update操作,都会应用到表t_t2上。
mysql> create table if not exists t_t1
    -> (
    ->  id int(3)
    -> )$
Query OK, 0 rows affected (0.00 sec)
mysql> create table if not exists t_t2
    -> (
    ->  id int(3)
    -> )$
Query OK, 0 rows affected (0.00 sec)
#创建存储过程
#向表db_test.t_t1中添加新记录,值为t_t1表的count(*)
mysql> delimiter $
mysql> drop procedure p_up_t1$
Query OK, 0 rows affected (0.00 sec)
mysql> create procedure p_up_t1
    -> (inout id int(3))
    -> begin 
    ->   select id as id_old_value;
    ->   select count(*) into id from t_t1;
    ->   select id as id_cout_t1;
    ->   insert into t_t1 values(id);
    ->   select id as id_count_t1_new;
    -> end$
Query OK, 0 rows affected (0.00 sec)
#创建触发器tri_t1
#把表t_t1中的列更新到表t_t2
mysql> drop trigger tri_t1$
Query OK, 0 rows affected (0.00 sec)
mysql> create trigger tri_t1
    -> after insert
    -> on t_t1
    -> for each row
    -> begin
    ->  insert into t_t2 set id = new.id;
    -> end$
Query OK, 0 rows affected (0.02 sec)
#触发器:更新t_t1表时,会级联更新t_t2表
mysql> create trigger tri_up_t1
    -> after update
    -> on t_t1
    -> for each row
    -> begin
    ->  update t_t2 set id = new.id
    ->   where id = old.id;
    -> end$
Query OK, 0 rows affected (0.02 sec)


#表t_t1,t_t2都为空
mysql> select count(*) from t_t1
    -> union
    -> select count(*) from t_t2$
#调用存储过程p_up_t1,向t_t1中添加记录,并更新t_t2
mysql> call p_up_t1(@id)$
+--------------+
| id_old_value |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)
+------------+
| id_cout_t1 |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)
+-----------------+
| id_count_t1_new |
+-----------------+
|               0 |
+-----------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
#查看表t_t1,t_t2中的内容是否一致
mysql> select * from t_t1
    -> union
    -> select * from t_t2$
+------+
| id   |
+------+
|    0 |
+------+
1 row in set (0.00 sec)
#更新表t_t1,会级联更新t_t2
mysql> select * from t_t2$
+------+
| id   |
+------+
|    0 |
+------+
1 rows in set (0.00 sec)
mysql> update t_t1
    -> set id=2
    -> where id=0$
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> select * from t_t2$
+------+
| id   |
+------+
|    2 |
+------+
1 rows in set (0.00 sec)
mysql>

你可能感兴趣的:(mysql中的事件、存储过程、触发器)