一、存储过程的定义
存储过程是存储在数据库目录中的一坨的声明性SQL语句。 Java,Python,PHP等应用程序可以调用存储过程。
MySQL是最受欢迎的开源RDBMS,被社区和企业广泛使用。 然而,在它发布的第一个十年期间,它不支持存储过程,存储函数,触发器和事件。自从MySQL 5.0版本以来,这些功能被添加到MySQL数据库引擎,使其更加灵活和强大。
二、存储过程的优点
#1、通常存储过程有助于提高应用程序的性能。当创建,存储过程被编译之后,就存储在数据库中。 但是,MySQL实现的存储过程略有不同。 MySQL存储过程按需编译。 在编译存储过程之后,MySQL将其放入缓存中。 MySQL为每个连接维护自己的存储过程高速缓存。 如果应用程序在单个连接中多次使用存储过程,则使用编译版本,否则存储过程的工作方式类似于查询。 # 2、存储过程有助于减少应用程序和数据库服务器之间的流量,因为应用程序不必发送多个冗长的SQL语句,而只能发送存储过程的名称和参数。 #3、存储的程序对任何应用程序都是可重用的和透明的。 存储过程将数据库接口暴露给所有应用程序,以便开发人员不必开发存储过程中已支持的功能。 #4、存储的程序是安全的。 数据库管理员可以向访问数据库中存储过程的应用程序授予适当的权限,而不向基础数据库表提供任何权限。
除了这些优点之外,存储过程有其自身的缺点,在数据库中使用它们之前,您应该注意这些缺点。
三、存储过程的缺点
#1、如果使用大量存储过程,那么使用这些存储过程的每个连接的内存使用量将会大大增加。 此外,如果您在存储过程中过度使用大量逻辑操作,则CPU使用率也会增加,因为数据库服务器的设计不当于逻辑运算。 #2、存储过程的构造使得开发具有复杂业务逻辑的存储过程变得更加困难。 #3、很难调试存储过程。只有少数数据库管理系统允许您调试存储过程。不幸的是,MySQL不提供调试存储过程的功能。 #4、开发和维护存储过程并不容易。开发和维护存储过程通常需要一个不是所有应用程序开发人员拥有的专业技能。这可能会导致应用程序开发和维护阶段的问题。
MySQL存储过程有自己的优点和缺点。开发应用程序时,您应该决定是否应该或不应该根据业务需求使用存储过程。
四、一个简单的Mysql存储过程示例
delimiter // create procedure b1() begin select * from blog; end // delimiter ;
解释:
1.第一个命令是delimiter //,它与存储过程语法无关。 delimter语句将标准分隔符 - 分号(;)更改为://。 在这种情况下,分隔符从分号(;)更改为双斜杠//。为什么我们必须更改分隔符? 因为我们想将存储过程作为整体传递给服务器,而不是让mysql工具一次解释每个语句。 在END关键字之后,使用分隔符//来指示存储过程的结束。 最后一个命令(DELIMITER;)将分隔符更改回分号(;)。
2.使用create procedure语句创建一个新的存储过程。在create procedure语句之后指定存储过程的名称。在这个示例中,存储过程的名称为:b1,并把括号放在存储过程的名字之后。
3.begin和end之间的部分称为存储过程的主体。将声明性SQL语句放在主体中以处理业务逻辑。 在这个存储过程中,我们使用一个简单的select语句来查询blog表中的数据。
# mysql中调用存储过程 call b1() #在python中基于pymysql调用 cursor.callproc('b1') print(cursor.fetchall())
五、声明变量
要在存储过程中声明变量,可以使用delclare语句,如下
DECLARE variable_name datatype(size) DEFAULT default_value;
下面来更详细地解释上面的语句:
首先,在DECLARE关键字后面要指定变量名。变量名必须遵循MySQL表列名称的命名规则。
其次,指定变量的数据类型及其大小。变量可以有任何MySQL数据类型,如INT,VARCHAR,DATETIME等。
第三,当声明一个变量时,它的初始值为NULL。但是可以使用DEFAULT关键字为变量分配默认值。
实现:
delimiter // create procedure b2() begin DECLARE n int DEFAULT 1; set n = 5; select * from blog where id = n; end // delimiter ; # mysql中调用存储过程 call b2();
六、存储过程传参
在现实应用中,开发的存储过程几乎都需要参数。这些参数使存储过程更加灵活和有用。 在MySQL中,参数有三种模式:IN,OUT或INOUT。
IN - 是默认模式。在存储过程中定义IN参数时,调用程序必须将参数传递给存储过程。 另外,IN参数的值被保护。这意味着即使在存储过程中更改了IN参数的值,在存储过程结束后仍保留其原始值。换句话说,存储过程只使用IN参数的副本。
OUT - 可以在存储过程中更改OUT参数的值,并将其更改后新值传递回调用程序。请注意,存储过程在启动时无法访问OUT参数的初始值。
INOUT - INOUT参数是IN和OUT参数的组合。这意味着调用程序可以传递参数,并且存储过程可以修改INOUT参数并将新值传递回调用程序。
在存储过程中定义参数的语法如下:
MODE param_name param_type(param_size)
根据存储过程中参数的目的,MODE可以是IN,OUT或INOUT。
param_name是参数的名称。参数的名称必须遵循MySQL中列名的命名规则。
在参数名之后是它的数据类型和大小。和变量一样,参数的数据类型可以是任何有效的MySQL数据类型
ps:如果存储过程有多个参数,则每个参数由逗号(,)分隔。
# 1.in delimiter // create procedure b3( in blogName varchar(30) ) begin select * from blog where NAME = blogName; end // delimiter ; #mysql中调用存储过程 call b3('第5篇'); #python中调用存储过程 cursor.callproc('b3',args = ('第5篇')); # 2.out delimiter // create procedure b4( in year int, out count int ) begin SELECT COUNT(1) into count FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y') having max(DATE_FORMAT(sub_time,'%Y')) = year ; set count = 6; end // delimiter ; call b4(2016,@count); select @count; #out只能当返回值 # 3.inout delimiter // create procedure b5( inout n1 int ) begin select * from blog where id > n1; end // delimiter ; #mysql中调用
set @n = 3;
call b5(@n);
select @n;
#在python中基于pymysql调用 cursor.callproc('b5',(4)) print(cursor.fetchall()) #查询select的查询结果 cursor.execute('select @n1') print(cursor.fetchall()) # inout:既可以传入又可以返回