本文记录了MySQL存储过程的一些核心知识点,详细内容请参考官方文档。文中的MySQL版本为5.7。
语法
|
- 存储过程可以加 db_name限定数据库,不加就使用默认数据库
- 默认情况下,MYSQL给存储过程创建者
ALTER ROUTINE
和EXECUTE
权限。
proc_parameter
默认IN,可以选择OUT,INOUT
proc_parameter
只支持IN
characteristic
- COMMENT用于写备注
- LANGUAGE这个server被忽略,只是为了符合SQL标准
- DETERMINISTIC和NOT DETERMINISTIC。这个只是创建者自己定义的,MYSQL不会做任何检查。但是如果把
NOT DETEMINISTIC
定义为DETERMINISTIC
,可能导致优化器做出错误的执行计划。相反,把DETEMINISTIC
定义为NOT DETERMINISTIC
可能让一些可用的优化措施无法使用。如果使用binary logging,需要参考Binary Logging of Stored Programs. { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
这组被server忽略- SQL SECURITY定义谁可以调用。DEFINER表示由DEFINER属性所指定的用户的权限来执行,INVOKER表示以调用这个存储过程的用户的权限来执行。默认DEFINER,且值为CURRENT_USER。如果用户没有过程中需要的权限,那么INVOKER类型过程的就无法调用。
routine_body
可以执行Compound-Statement.以及DDL语句,同时存储过程支持事务。
Compiund Statement
BEGIN END语法
语句块,可嵌套,可结合Lable使用。
Label语法
可用于标记BEGIN,LOOP,REPEAT以及WHILE语句。可以用ITERATE和LEAVE指令控制流程。
DECLARE语法
声明变量,条件处理或者游标。限制如下:
- 只能在BEGIN语句中,且必须在最前面
- 必须按照变量,游标,条件处理的顺序声明。
变量
所用DECLARE声明,赋值可以使用SET语法,SELECT ... INTO var_list
或者 FETCH ... INTO var_list
定义格式:
|
控制流程
和C语言的类比
MYSQL | C | 备注 |
---|---|---|
CASE | switch | |
IF | if | |
LOOP | while(1){} | 用ITERATE模拟continue,LEAVE模拟break |
REPATE | do…while | 用ITERATE模拟continue,LEAVE模拟break |
WHILE | while | 用ITERATE模拟continue,LEAVE模拟break |
游标
游标使用的流程遵循:定义,OPEN,FETCH,CLOSE。语法如下
|
条件处理
程序执行过程中可能出现一些需要特殊处理的情况,比如继续执行还是推出程序?可以为一个条件定义处理器,条件也可以被命名。
- 命名条件使用DECLARE … CONDITION 语法,此步骤可选。
- 定义处理器使用DECLARE … HANDLER 语法
- 自己抛出一个条件使用SIGNAL 语法,定义条件处理器中继续抛出使用RESIGNAL 语法
- 获取错误内容使用 GET DIAGNOSTICS 语法
例子:
|
常用的处理器:
常见问题
有许多常见问题是因为MySQL本身的一些限制,可以参考:Restrictions on Stored Programs。下面记录一些常见的或者我碰到的问题,欢迎补充。
FETCH拿不到任何记录
如果定义的变量名和SELECT的字段名一样,那么可能出现问题,这是MySQL的一个bug,解决方案是不要使变量名和字段名一样。
ERROR:Cursor declaration after handler declaration
DECLARATION定义顺序错误,类似的还有Variable or condition declaration after cursor or handler declaration
错误
参考资料
- https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
- http://chuiliu.github.io/2016/02/28/mysql%E7%9A%84definer%E5%92%8Cinvoker/
- https://my.oschina.net/u/1424662/blog/485118
- https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-compound-statements.html
- http://www.yiibai.com/mysql/signal-resignal.html
- http://www.cnblogs.com/langtianya/p/5534222.html
- https://stackoverflow.com/questions/40661398/mysql-cursor-fetch-null