-
存储过程
-
概念
- 存储过程是一组为了完成特定功能的 SQL 语句集合。使用存储过程的目的是将常用或复杂的工作预先用 SQL 语句写好并用一个指定名称存储起来,这个过程经编译和优化后存储在数据库服务器中,因此称为存储过程。对于调用者来说,存储过程封装了 SQL 语句,调用者无需考虑逻辑功能的具体实现过程。只是简单调用即可,它可以被 Java 和 C# 等编程语言调用。
- 作用:提高数据库处理速度
- 用途:存储过程可以用来转换数据、数据迁移、制作报表,它类似于编程语言,一次执行成功,就可以随时被调用,完成指定的功能操作。
- 注意:5.0以前不支持存储过程
- 存储过程是一组为了完成特定功能的 SQL 语句集合。使用存储过程的目的是将常用或复杂的工作预先用 SQL 语句写好并用一个指定名称存储起来,这个过程经编译和优化后存储在数据库服务器中,因此称为存储过程。对于调用者来说,存储过程封装了 SQL 语句,调用者无需考虑逻辑功能的具体实现过程。只是简单调用即可,它可以被 Java 和 C# 等编程语言调用。
-
语法
-
创建存储过程
- CREATE PROCEDURE <过程名> ( [过程参数[,…] ] ) <过程体> [过程参数[,…] ] 格式 [ IN | OUT | INOUT ] <参数名> <类型>
-
过程名
- 存储过程的名称,默认在当前数据库中创建。若需要在特定数据库中创建存储过程,则要在名称前面加上数据库的名称,即 db_name.sp_name。
- 注意的是,名称应当尽量避免选取与 MySQL 内置函数相同的名称,否则会发生错误。
- 存储过程的名称,默认在当前数据库中创建。若需要在特定数据库中创建存储过程,则要在名称前面加上数据库的名称,即 db_name.sp_name。
-
过程参数
- 存储过程的参数列表。其中,<参数名>为参数名,<类型>为参数的类型(可以是任何有效的 MySQL 数据类型)。当有多个参数时,参数列表中彼此间用逗号分隔。存储过程可以没有参数(此时存储过程的名称后仍需加上一对括号),也可以有 1 个或多个参数。
- MySQL 存储过程支持三种类型的参数,即输入参数、输出参数和输入/输出参数,分别用 IN、OUT 和 INOUT 三个关键字标识。其中,输入参数可以传递给一个存储过程,输出参数用于存储过程需要返回一个操作结果的情形,而输入/输出参数既可以充当输入参数也可以充当输出参数。
- 需要注意的是,参数的取名不要与数据表的列名相同,否则尽管不会返回出错信息,但是存储过程的 SQL 语句会将参数名看作列名,从而引发不可预知的结果。
- 存储过程的参数列表。其中,<参数名>为参数名,<类型>为参数的类型(可以是任何有效的 MySQL 数据类型)。当有多个参数时,参数列表中彼此间用逗号分隔。存储过程可以没有参数(此时存储过程的名称后仍需加上一对括号),也可以有 1 个或多个参数。
-
过程体
- 存储过程的主体部分,也称为存储过程体,包含在过程调用的时候必须执行的 SQL 语句。这个部分以关键字 BEGIN 开始,以关键字 END 结束。若存储过程体中只有一条 SQL 语句,则可以省略 BEGIN-END 标志。
- 在存储过程的创建中,经常会用到一个十分重要的 MySQL 命令,即 DELIMITER 命令,特别是对于通过命令行的方式来操作 MySQL 数据库的使用者,更是要学会使用该命令。
- 在 MySQL 中,服务器处理 SQL 语句默认是以分号作为语句结束标志的。然而,在创建存储过程时,存储过程体可能包含有多条 SQL 语句,这些 SQL 语句如果仍以分号作为语句结束符,那么 MySQL 服务器在处理时会以遇到的第一条 SQL 语句结尾处的分号作为整个程序的结束符,而不再去处理存储过程体中后面的 SQL 语句,这样显然不行。
- 为解决以上问题,通常使用 DELIMITER 命令将结束命令修改为其他字符。语法格式如下
-
DELIMITER $$
将结束符替换问其他字符,不然mysql会以为语句结束- $$ 是用户定义的结束符,通常这个符号可以是一些特殊的符号,如两个“?”或两个“¥”等。
- 当使用 DELIMITER 命令时,应该避免使用反斜杠“\”字符,因为它是 MySQL 的转义字符
- 若希望换回默认的分号“;”作为结束标志,则在 MySQL 命令行客户端输入下列语句即可:
- mysql > DELIMITER ;
- 注意:DELIMITER 和分号“;”之间一定要有一个空格。在创建存储过程时,必须具有 CREATE ROUTINE 权限。
- $$ 是用户定义的结束符,通常这个符号可以是一些特殊的符号,如两个“?”或两个“¥”等。
- 存储过程的主体部分,也称为存储过程体,包含在过程调用的时候必须执行的 SQL 语句。这个部分以关键字 BEGIN 开始,以关键字 END 结束。若存储过程体中只有一条 SQL 语句,则可以省略 BEGIN-END 标志。
- CREATE PROCEDURE <过程名> ( [过程参数[,…] ] ) <过程体> [过程参数[,…] ] 格式 [ IN | OUT | INOUT ] <参数名> <类型>
-
修改存储过程
- ALTER PROCEDURE 存储过程名 [ 特征 ... ]
-
特征指定了存储过程的特性,可能的取值有:
- CONTAINS SQL 表示子程序包含 SQL 语句,但不包含读或写数据的语句。
- NO SQL 表示子程序中不包含 SQL 语句。
- READS SQL DATA 表示子程序中包含读数据的语句。
- MODIFIES SQL DATA 表示子程序中包含写数据的语句。
- SQL SECURITY { DEFINER |INVOKER } 指明谁有权限来执行。
- DEFINER 表示只有定义者自己才能够执行。
- INVOKER 表示调用者可以执行。
- COMMENT \'string\' 表示注释信息。
- CONTAINS SQL 表示子程序包含 SQL 语句,但不包含读或写数据的语句。
- ALTER PROCEDURE 存储过程名 [ 特征 ... ]
-
查看存储过程
-
查看存储过程的状态
- SHOW PROCEDURE STATUS LIKE 存储过程名;
- LIKE 存储过程名用来匹配存储过程的名称,LIKE 不能省略。
- SHOW PROCEDURE STATUS LIKE 存储过程名;
-
查看存储过程的定义
- SHOW CREATE PROCEDURE 存储过程名;
- SHOW CREATE PROCEDURE 存储过程名;
- SHOW STATUS 语句只能查看存储过程是操作的哪一个数据库、存储过程的名称、类型、谁定义的、创建和修改时间、字符编码等信息。但是,这个语句不能查询存储过程的集体定义,如果需要查看详细定义,需要使用 SHOW CREATE 语句。
-
查看存储过程的状态
- 调用方式:CALL存储过程名字(参数)
-
创建存储过程
-
show procedure status
- 显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过 程名称,创建时间等
- 显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过 程名称,创建时间等
-
参数等,into语句说明
-
IN 输入参数:
- 表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
- 表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
-
OUT 输出参数:
- 该值可在存储过程内部被改变,并可返回
- 调用out过程是用参数用@符号定义变量,无论set设不设值,out参数到语句内部为null,只能在内部赋值。
- 该值可在存储过程内部被改变,并可返回
-
INOUT 输入输出参数:
- 调用时指定,并且可被改变和返回
- 用inout是可用set @ 变量名设值
- 调用时指定,并且可被改变和返回
-
存储过程中select into的使用
-
SELECT col_name[,...] INTO var_name[,...] table_expr
- ①col_name:要从数据库中查询的列字段名;
- ②var_name:变量名,列字段名按照在列清单和变量清单中的位置对应,将查询得到的值赋给对应位置的变量;但要区分out和inout区别,out直接能获得返回值,因为它只要进入就为null,而inout在外面被set设置后就相当于in。
- ③table_expr:SELECT语句中的其余部分,包括可选的FROM子句和WHERE子句。
- ①col_name:要从数据库中查询的列字段名;
- 在MySQL存储过程中使用SELECT …INTO语句为变量赋值:
- 用来将查询返回的一行的各个列值保存到局部变量中。
-
要求:
- 查询的结果集中只能有1行。
- 查询的结果集中只能有1行。
-
SELECT col_name[,...] INTO var_name[,...] table_expr
-
IN 输入参数:
-
概念
-
拓展
-
存储过程的信息都存储在 information_schema 数据库下的 Routines 表中,可以通过查询该表的记录来查询存储过程的信息,SQL 语句如下:
- SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=存储过程名;
- 在 information_schema 数据库下的 routines 表中,存储着所有存储过程的定义。所以,使用 SELECT 语句查询 routines 表中的存储过程和函数的定义时,一定要使用 routine_name 字段指定存储过程的名称,否则,将查询出所有的存储过程的定义。
- SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=存储过程名;
-
存储过程的信息都存储在 information_schema 数据库下的 Routines 表中,可以通过查询该表的记录来查询存储过程的信息,SQL 语句如下:
-
例子
-
无参:创建名称为 ShowStuScore 的存储过程,存储过程的作用是从学生成绩信息表中查询学生的成绩信息,输入的 SQL 语句和执行过程如下所示。
mysql> DELIMITER //
mysql> CREATE PROCEDURE ShowStuScore()
-> BEGIN
-> SELECT * FROM tb_students_score;
-> END //
Query OK, 0 rows affected (0.09 sec)
结果显示 ShowStuScore 存储过程已经创建成功。- 有参:创建名称为 GetScoreByStu 的存储过程,输入参数是学生姓名。存储过程的作用是通过输入的学生姓名从学生成绩信息表中查询指定学生的成绩信息,输入的 SQL 语句和执行过程如下所示。
mysql> DELIMITER //
mysql> CREATE PROCEDURE GetScoreByStu
-> (IN name VARCHAR(30))
-> BEGIN
-> SELECT student_score FROM tb_students_score
-> WHERE student_name=name;
-> END //
Query OK, 0 rows affected (0.01 sec)
- 有参:创建名称为 GetScoreByStu 的存储过程,输入参数是学生姓名。存储过程的作用是通过输入的学生姓名从学生成绩信息表中查询指定学生的成绩信息,输入的 SQL 语句和执行过程如下所示。
-
无参:创建名称为 ShowStuScore 的存储过程,存储过程的作用是从学生成绩信息表中查询学生的成绩信息,输入的 SQL 语句和执行过程如下所示。
-
触发器
-
概念
- MySQL 的触发器和存储过程一样,都是嵌入到 MySQL 中的一段程序,是 MySQL 中管理数据的有力工具。不同的是执行存储过程要使用 CALL 语句来调用,而触发器的执行不需要使用 CALL 语句来调用,也不需要手工启动,而是通过对数据表的相关操作来触发、激活从而实现执行。比如当对 student 表进行操作(INSERT,DELETE 或 UPDATE)时就会激活它执行。
-
引发触发器执行的事件一般有
- 在学生表中添加一条关于学生的记录时,学生的总数就必须同时改变。
- 增加一条学生记录时,需要检查年龄是否符合范围要求。
- 删除一条学生信息时,需要删除其成绩表上的对应记录。
- 删除一条数据时,需要在数据库存档表中保留一个备份副本。
- 在学生表中添加一条关于学生的记录时,学生的总数就必须同时改变。
-
触发器的优缺点
- 触发器的执行是自动的,当对触发器相关表的数据做出相应的修改后立即执行。
- 触发器可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。
- 触发器可以实现表数据的级联更改,在一定程度上保证了数据的完整性。
- 触发器的执行是自动的,当对触发器相关表的数据做出相应的修改后立即执行。
- MySQL 的触发器和存储过程一样,都是嵌入到 MySQL 中的一段程序,是 MySQL 中管理数据的有力工具。不同的是执行存储过程要使用 CALL 语句来调用,而触发器的执行不需要使用 CALL 语句来调用,也不需要手工启动,而是通过对数据表的相关操作来触发、激活从而实现执行。比如当对 student 表进行操作(INSERT,DELETE 或 UPDATE)时就会激活它执行。
-
MySQL 支持的触发器
- 在实际使用中,MySQL 所支持的触发器有三种:INSERT 触发器、UPDATE 触发器和 DELETE 触发器。
- 在实际使用中,MySQL 所支持的触发器有三种:INSERT 触发器、UPDATE 触发器和 DELETE 触发器。
-
语法
-
创建触发器
- CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
-
其中
- trigger_name:标识触发器名称,用户自行指定;
- trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
- trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
- tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
- trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。
- 由此可见,可以建立6种触发器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、AFTER UPDATE、AFTER DELETE。
- 另外有一个限制是不能同时在一个表上建立2个相同类型的触发器,因此在一个表上最多建立6个触发器。
- trigger_name:标识触发器名称,用户自行指定;
-
trigger_time
-
触发时机
- 指定触发器的触发时间。如果指定为BEFORE,则表示在执行DML操作之前触发,以便防止某些错误操作发生或实现某些业务规则;如果指定为AFTER,则表示在执行DML操作之后触发,以便记录该操作或做某些事后处理。
- 指定触发器的触发时间。如果指定为BEFORE,则表示在执行DML操作之前触发,以便防止某些错误操作发生或实现某些业务规则;如果指定为AFTER,则表示在执行DML操作之后触发,以便记录该操作或做某些事后处理。
-
触发时机
-
trigger_event 详解
- MySQL 除了对 INSERT、UPDATE、DELETE 基本操作进行定义外,还定义了 LOAD DATA 和 REPLACE 语句,这两种语句也能引起上述6中类型的触发器的触发。
- LOAD DATA 语句用于将一个文件装入到一个数据表中,相当与一系列的 INSERT 操作。
- REPLACE 语句一般来说和 INSERT 语句很像,只是在表中有 primary key 或 unique 索引时,如果插入的数据和原来 primary key 或 unique 索引一致时,会先删除原来的数据,然后增加一条新数据,也就是说,一条 REPLACE 语句有时候等价于一条。
- INSERT 语句,有时候等价于一条 DELETE 语句加上一条 INSERT 语句。
- INSERT 型触发器:插入某一行时激活触发器,可能通过 INSERT、LOAD DATA、REPLACE 语句触发;
- UPDATE 型触发器:更改某一行时激活触发器,可能通过 UPDATE 语句触发;
- DELETE 型触发器:删除某一行时激活触发器,可能通过 DELETE、REPLACE 语句触发。
- MySQL 除了对 INSERT、UPDATE、DELETE 基本操作进行定义外,还定义了 LOAD DATA 和 REPLACE 语句,这两种语句也能引起上述6中类型的触发器的触发。
-
BEGIN … END 详解
-
语法:
- BEGIN [statement_list] END
- 其中,statement_list 代表一个或多个语句的列表,列表内的每条语句都必须用分号(;)来结尾。
- 而在MySQL中,分号是语句结束的标识符,遇到分号表示该段语句已经结束,MySQL可以开始执行了。因此,解释器遇到statement_list 中的分号后就开始执行,然后会报出错误,因为没有找到和 BEGIN 匹配的 END。
- 这时就会用到 DELIMITER 命令(DELIMITER 是定界符,分隔符的意思),它是一条命令,不需要语句结束标识,语法为:
- DELIMITER new_delemiter
- new_delemiter 可以设为1个或多个长度的符号,默认的是分号(;),我们可以把它修改为其他符号,如$:
- DELIMITER $
- 在这之后的语句,以分号结束,解释器不会有什么反应,只有遇到了$,才认为是语句结束。注意,使用完之后,我们还应该记得把它给修改回来。
- BEGIN [statement_list] END
-
语法:
- CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
-
创建触发器
-
一个完整的触发器案例
-
变量详解
-
MySQL 中使用 DECLARE 来定义一局部变量,该变量只能在 BEGIN … END 复合语句中使用,并且应该定义在复合语句的开头,即在其他语句之前,语法为:
- DECLARE var_name[,...] type [DEFAULT value]
- DECLARE var_name[,...] type [DEFAULT value]
- 其中:
- var_name 为变量名称,同 SQL 语句一样,变量名不区分大小写;type 为 MySQL 支持的任何数据类型;可以同时定义多个同类型的变量,用逗号隔开;变量初始值为 NULL,如果需要,可以使用 DEFAULT 子句提供默认值,值可以被指定为一个表达式。
-
对变量赋值采用 SET 语句,语法为:
- SET var_name = expr [,var_name = expr] ...
- SET var_name = expr [,var_name = expr] ...
-
MySQL 中使用 DECLARE 来定义一局部变量,该变量只能在 BEGIN … END 复合语句中使用,并且应该定义在复合语句的开头,即在其他语句之前,语法为:
-
NEW 与 OLD 详解
- 上述示例中使用了NEW关键字,和 MS SQL Server 中的 INSERTED 和 DELETED 类似,MySQL 中定义了 NEW 和 OLD,用来表示
- 触发器的所在表中,触发了触发器的那一行数据。
- 具体地:
- 在 INSERT 型触发器中,NEW 用来表示将要(BEFORE)或已经(AFTER)插入的新数据;
- 在 UPDATE 型触发器中,OLD 用来表示将要或已经被修改的原数据,NEW 用来表示将要或已经修改为的新数据;
- 在 DELETE 型触发器中,OLD 用来表示将要或已经被删除的原数据;
- 使用方法: NEW.columnName (columnName 为相应数据表某一列名)
- 另外,OLD 是只读的,而 NEW 则可以在触发器中使用 SET 赋值,这样不会再次触发触发器,造成循环调用(如每插入一个学生前,都在其学号前加“2013”)。
- 上述示例中使用了NEW关键字,和 MS SQL Server 中的 INSERTED 和 DELETED 类似,MySQL 中定义了 NEW 和 OLD,用来表示
-
查看触发器
-
和查看数据库(show databases;)查看表格(show tables;)一样,查看触发器的语法如下:
- SHOW TRIGGERS [FROM schema_name];
- SHOW TRIGGERS [FROM schema_name];
- 其中,schema_name 即 Schema 的名称,在 MySQL 中 Schema 和 Database 是一样的,也就是说,可以指定数据库名,这样就
- 不必先“USE database_name;”了。
-
和查看数据库(show databases;)查看表格(show tables;)一样,查看触发器的语法如下:
-
删除触发器
-
和删除数据库、删除表格一样,删除触发器的语法如下:
- DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
- DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
-
和删除数据库、删除表格一样,删除触发器的语法如下:
-
触发器的执行顺序
- 我们建立的数据库一般都是 InnoDB 数据库,其上建立的表是事务性表,也就是事务安全的。这时,若SQL语句或触发器执行失败,MySQL 会回滚事务,有:
- ①如果 BEFORE 触发器执行失败,SQL 无法正确执行。
- ②SQL 执行失败时,AFTER 型触发器不会触发。
- ③AFTER 类型的触发器执行失败,SQL 会回滚
- 我们建立的数据库一般都是 InnoDB 数据库,其上建立的表是事务性表,也就是事务安全的。这时,若SQL语句或触发器执行失败,MySQL 会回滚事务,有:
代码练习: -
概念
相关文章: