Mysql存储过程学习笔记css
经常使用的操做数据库语言SQL语句在执行的时候须要要先编译,而后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户经过指定存储过程的名字并给定参数(若是该存储过程带有参数)来调用执行它。html
一个存储过程是一个可编程的函数,它在数据库中建立并保存。它能够有SQL语句和一些特殊的控制结构组成。当但愿在不一样的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是很是有用的。数据库中的存储过程能够看作是对编程中面向对象方法的模拟。它容许控制数据的访问方式。前端
存储过程一般有如下优势:mysql
(1).存储过程加强了SQL语言的功能和灵活性。存储过程能够用流控制语句编写,有很强的灵活性,能够完成复杂的判断和较复杂的运算。sql
(2).存储过程容许标准组件是编程。存储过程被建立后,能够在程序中被屡次调用,而没必要从新编写该存储过程的SQL语句。并且数据库专业人员能够随时对存储过程进行修改,对应用程序源代码毫无影响。数据库
(3).存储过程能实现较快的执行速度。若是某一操做包含大量的Transaction-SQL代码或分别被屡次执行,那么存储过程要比批处理的执行速度快不少。由于存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,而且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。express
(4).存储过程能过减小网络流量。针对同一个数据库对象的操做(如查询、修改),若是这一操做所涉及的Transaction-SQL语句被组织程存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增长了网络流量并下降了网络负载。编程
(5).存储过程可被做为一种安全机制来充分利用。系统管理员经过执行某一存储过程的权限进行限制,可以实现对相应的数据的访问权限的限制,避免了非受权用户对数据的访问,保证了数据的安全。后端
存储过程是数据库存储的一个重要的功能,可是MySQL在5.0之前并不支持存储过程,这使得MySQL在应用上大打折扣。好在MySQL 5.0终于开始已经支持存储过程,这样便可以大大提升数据库的处理速度,同时也能够提升数据库编程的灵活性。安全
(1). 格式
MySQL存储过程建立的格式:CREATE PROCEDURE 过程名 ([过程参数[,...]])
[特性 ...] 过程体
|
这里先举个例子:
注:
(1)这里须要注意的是DELIMITER //和DELIMITER ;两句,DELIMITER是分割符的意思,由于MySQL默认以";"为分隔符,若是咱们没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错,因此要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";"当作存储过程当中的代码,不会执行这些代码,用完了以后要把分隔符还原。
(2)存储过程根据须要可能会有输入、输出、输入输出参数,这里有一个输出参数s,类型是int型,若是有多个参数用","分割开。
(3)过程体的开始与结束使用BEGIN与END进行标识。
这样,咱们的一个MySQL存储过程就完成了,是否是很容易呢?看不懂也不要紧,接下来,咱们详细的讲解。
MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT,形式如:
CREATE PROCEDURE([[IN |OUT |INOUT ] 参数名 数据类形...])
IN 输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程当中修改该参数的值不能被返回,为默认值
OUT 输出参数:该值可在存储过程内部被改变,并可返回
INOUT 输入输出参数:调用时指定,而且可被改变和返回
小例子:
存储过程为:
|
|
调用存储过程:
(1).变量定义:
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype为MySQL的数据类型,如:int, float, date, varchar(length)
DECLARE l_int int unsigned default 4000000;
DECLARE l_numeric number(8,2) DEFAULT 9.95;
DECLARE l_date date DEFAULT '1999-12-31';
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
(2).变量赋值
SET 变量名 = 表达式值 [,variable_name = expression ...]
(3).变量做用域
内部的变量在其做用域范围内享有更高的优先权,当执行到end。变量时,内部变量消失,此时已经在其做用域外,变量再也不可见了,应为在存储过程外不再能找到这个申明的变量,可是你能够经过out参数或者将其值指派给会话变量来保存其值。
|
定义条件和处理程序是事先定义程序执行过程当中可能遇到的问题。而且能够在处理程序中定义解决这些问题的办法。这种方式能够提早预测可能出现的问题,并提出解决办法。这样能够加强程序处理问题的能力,避免程序异常中止。MySQL中都是经过DECLARE关键字来定义条件和处理程序。本小节中将详细讲解如何定义条件和处理程序。
(1).定义条件
MySQL中可使用DECLARE关键字来定义条件。其基本语法以下:
DECLARE condition_name CONDITION FOR condition_value
condition_value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code
其中,condition_name参数表示条件的名称;condition_value参数表示条件的类型;sqlstate_value参数和mysql_error_code参数均可以表示MySQL的错误。例如ERROR 1146 (42S02)中,sqlstate_value值是42S02,mysql_error_code值是1146。
【示例】 下面定义"ERROR 1146 (42S02)"这个错误,名称为can_not_find。能够用两种不一样的方法来定义,代码以下:
//方法一:使用sqlstate_value
DECLARE can_not_find CONDITION FOR SQLSTATE '42S02' ;
//方法二:使用mysql_error_code
DECLARE can_not_find CONDITION FOR 1146 ;
(2).定义处理程序
MySQL中可使用DECLARE关键字来定义处理程序。其基本语法以下:
DECLARE handler_type HANDLER FOR
condition_value[,...] sp_statement
handler_type:
CONTINUE | EXIT | UNDO
condition_value:
SQLSTATE [VALUE] sqlstate_value |
condition_name | SQLWARNING
| NOT FOUND | SQLEXCEPTION | mysql_error_code
其中,handler_type参数指明错误的处理方式,该参数有3个取值。这3个取值分别是CONTINUE、EXIT和UNDO。CONTINUE表示遇到错误不进行处理,继续向下执行;EXIT表示遇到错误后立刻退出;UNDO表示遇到错误后撤回以前的操做,MySQL中暂时还不支持这种处理方式。
注意:一般状况下,执行过程当中遇到错误应该马上中止执行下面的语句,而且撤回前面的操做。可是,MySQL中如今还不能支持UNDO操做。
所以,遇到错误时最好执行EXIT操做。若是事先可以预测错误类型,而且进行相应的处理,那么能够执行CONTINUE操做。
condition_value参数指明错误类型,该参数有6个取值。sqlstate_value和mysql_error_code与条件定义中的是同一个意思。
condition_name是DECLARE定义的条件名称。SQLWARNING表示全部以01开头的sqlstate_value值。NOT FOUND表示全部以02开头的
sqlstate_value值。SQLEXCEPTION表示全部没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值。sp_statement表示一些存储过程或函
数的执行语句。
【示例】 下面是定义处理程序的几种方式。代码以下:
//方法一:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SET @info='CAN NOT FIND';
//方法二:捕获mysql_error_code
DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';
//方法三:先定义条件,而后调用
DECLARE can_not_find CONDITION FOR 1146 ;
DECLARE CONTINUE HANDLER FOR can_not_find SET
@info='CAN NOT FIND';
//方法四:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
//方法五:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';
//方法六:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
上述代码是6种定义处理程序的方法。
第一种方法是捕获sqlstate_value值。若是遇到sqlstate_value值为42S02,执行CONTINUE操做,而且输出"CAN NOT FIND"信息。
第二种方法是捕获mysql_error_code值。若是遇到mysql_error_code值为1146,执行CONTINUE操做,而且输出"CAN NOT FIND"信息。
第三种方法是先定义条件,而后再调用条件。这里先定义can_not_find条件,遇到1146错误就执行CONTINUE操做。
第四种方法是使用SQLWARNING。SQLWARNING捕获全部以01开头的sqlstate_value值,而后执行EXIT操做,而且输出"ERROR"信息。
第五种方法是使用NOT FOUND。NOT FOUND捕获全部以02开头的sqlstate_value值,而后执行EXIT操做,而且输出"CAN NOT FIND"信息。
第六种方法是使用SQLEXCEPTION。SQLEXCEPTION捕获全部没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值,而后执行EXIT操做,而且输出"ERROR"信息。
咱们像知道一个数据库下面有那些表,咱们通常采用show tables;进行查看。那么咱们要查看某个数据库下面的存储过程,是否也能够采用呢?答案是,咱们能够查看某个数据库下面的存储过程,可是是令一钟方式。
咱们能够用
select name from mysql.proc where db=’数据库名’;
或者
select routine_name from information_schema.routines where routine_schema='数据库名';
或者
show procedure status where db='数据库名';
进行查询。
若是咱们想知道,某个存储过程的详细,那咱们又该怎么作呢?是否是也能够像操做表同样用describe 表名进行查看呢?
答案是:咱们能够查看存储过程的详细,可是须要用另外一种方法:
SHOW CREATE PROCEDURE 数据库.存储过程名;
就能够查看当前存储过程的详细。
删除一个存储过程比较简单,和删除表同样:DROP PROCEDURE从MySQL的表格中删除一个或多个存储过程。
|
(1). if-then -else语句
|
(2). case语句:
|
(1).WHILE...END WHILE
(2).
|
REPEAT...END REPEAT
(3).LOOP...END LOOP:
|
LOOP 循环不须要初始条件,这点和WHILE循环类似,同时和REPEAT循环同样不须要结束条件,LEAVE 语句的意思是离开循环
(1).ITERATE:
经过引用符合语句的标号,来从新开始符合语句
|
|
(1).字符串类:
|
(2).数学类
|
(3).日期时间类
|
|
|
|
|
||
|
|
|
22. 学习prepare
|
|
右击存储过程---"Debug"--"Step Into", 以下图
先择"Stop Into"后,若是你的存储过程有参数,则为弹出窗体提示输入参数值,若是没有,则不直接运行;
存储过程会从"begin"开始执行,而后点又上角的"step over"(F10), 单步执行。
查看变量值:选中变量,点右键,选择"Add Wath", 这个变量就会在"Watches"这个视图区出现,若是你单步运行到这个变量值,则能够看见了,这样就能够调试,变量值是否正确,有错误没,循环次数等。
(1) DECLARE…HANDLER语句
|
语法以下
a、condition_value [,condition_value],这个的话说明能够包括多种状况(方括弧表示可选的),也就是一个handler能够定义成针对多种状况进行相应的操做;另外condition_value能够包括的值有上面列出来的6种:
一、mysql_error_code,这个表示MySQL的错误代码,错误代码是一个数字,完成是由mysql本身定义的,这个值能够参考mysql数据库错误代码及信息。
二、SQLSTATE [VALUE] sqlstate_value,这个同错误代码相似造成一一对应的关系,它是一个5个字符组成的字符串,关键的地方是它从ANSI SQL和ODBC这些标准中引用过来的,所以更加标准化,而不像上面的error_code彻底是mysql本身定义给本身用的,这个和第一个相似也能够参考mysql数据库错误代码及信息。
三、condtion_name,这个是条件名称,它使用DECLARE...CONDITION语句来定义,这个后面咱们会介绍如何定义本身的condition_name。
四、SQLWARNING,表示SQLTATE中的字符串以‘01’起始的那些错误,好比Error: 1311
SQLSTATE:01000
(ER_SP_UNINIT_VAR
)
五、NOT FOUND,表示SQLTATE中的字符串以‘02’起始的那些错误,好比Error: 1329
SQLSTATE: 02000
(ER_SP_FETCH_NO_DATA
),其实这个错误就是用在咱们介绍游标的那个问题所出现的状况,也就是没有fetch到记录,也就是咱们游标到记录的尾巴了的状况。
六、SQLEXCEPTION,表示SQLSTATE中的字符串不是以'00'、'01'、'02' 起始的那些错误,这里'00'起始的SQLSTATE其实表示的是成功执行而不是错误,另外两个就是上面的4和5的两种状况。
上面的6种状况其实能够分为两类,一类就是比较明确的处理,就是对指定的错误状况进行处理,包括一、二、3这三种方式;另外一类是对对应类型的错误的处理,就是对某一群错误的处理,包括四、五、6这三种方式。这个是介绍了condition_value。另外还要注意的一个内容是MySQL在默认状况下(也就是咱们没有定义处理错误的方法-handler)本身的错误处理机制:一、对于SQLWARNING和NOT FOUND的处理方法就是无视错误继续执行,因此在游标的例子里面若是咱们没有对repeat的条件判断的那个值作个no_more_products=1的handler来处理,那么循环就会一直下去。二、对于SQLEXCEPTION的话,其默认的处理方法是在出现错误的地方就终止掉了。
b、statement,这个比较简单就是当出现某种条件/错误时,咱们要执行的语句,能够是简单的如 SET var = value这样的简单的语句,也能够是复杂的多行的语句,多行的话可使用BEGIN ..... END这里把语句包括在里面(这个比如delphi里面的状况,注意到咱们的存储过程也是多行的,因此也要BEGIN .... END)。
c、handler_action,这个表示当执行完上面的statement后,但愿执行怎样的动做,这里包括CONTINUE、EXIT、UNDO,表示继续、退出、撤销(暂时不支持)。这边就是两种动做,其实这两种动做在上面也说过了,CONTINUE就是一个是SQLWARNING和NOT FOUND的默认处理方法,而EXIT就是SQLEXCEPTION的默认处理方法。
来看个简单的例子,这里建立一个对SQLSTATE的代码为'23000'的错误(重复的主键)进行处理的HANDLER,每次发生时咱们对变量@x进行增长1:
|
经过结果咱们知道出现了两次插入的记录同原有的记录出现主键重复的状况。固然这个是由下面这个代码触发的。
INSERT INTO products values(1,default,default,default,default,default);
(2) DECLARE...CONDITION语句
|
这个语句实际上是为了让咱们的错误条件更加的清晰明了化的,对于上面的状况,像SQLSTATE '23000'这种表示是一种很不直观的方法,要经过相应的文档去对应,阅读起来比较不方便。而DECLARE....CONDITION能够对条件定义相对应的名称,看个例子就清楚了:
固然在上面的例子咱们没有用到BEGIN....END,咱们只有一行SET @x=@x+1;这里咱们用duplicate_key这个条件名称来对应到SQLSTATE '23000'上面,这样查看起来更加的直观。这你duplicate_key就是咱们上面介绍DECLARE....HANDLER时候的那个condition_name。
INSERT IGNORE INTO与INSERT INTO的区别就是INSERT IGNORE INTO会忽略数据库中已经存在 的数据,若是数据库没有数据,就插入新的数据,若是有数据的话就跳过这条数据。这样就能够保留数据库中已经存在数据,达到在间隙中插入数据的目的。
MyISAM 和InnoDB 讲解
InnoDB和MyISAM是许多人在使用MySQL时最经常使用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差异为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,可是不提供事务支持,而InnoDB提供事务支持以及外部键等高级数据库功能。
如下是一些细节和具体实现的差异:
◆1.InnoDB不支持FULLTEXT类型的索引。
◆2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,可是MyISAM只要简单的读出保存好的行数便可。注意的是,当count(*)语句包含 where条件时,两种表的操做是同样的。
◆3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中,能够和其余字段一块儿创建联合索引。
◆4.DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除。
◆5.LOAD TABLE FROM MASTER操做对InnoDB是不起做用的,解决方法是首先把InnoDB表改为MyISAM表,导入数据后再改为InnoDB表,可是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表,例如update table set num=1 where name like “%aaa%”
两种类型最主要的差异就是Innodb 支持事务处理与外键和行级锁。而MyISAM不支持.因此MyISAM每每就容易被人认为只适合在小项目中使用。
做为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,若是数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来讲的话,MyISAM绝对是首选。
缘由以下:
一、平台上承载的大部分项目是读多写少的项目,而MyISAM的读性能是比Innodb强很多的。
二、MyISAM的索引和数据是分开的,而且索引是有压缩的,内存使用率就对应提升了很多。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会形成Innodb比MyISAM体积庞大不小。
三、常常隔1,2个月就会发生应用开发人员不当心update一个表where写的范围不对,致使这个表无法正经常使用了,这个时候MyISAM的优越性就体现出来了,随便从当天拷贝的压缩包取出对应表的文件,随便放到一个数据库目录下,而后dump成sql再导回到主库,并把对应的binlog补上。若是是Innodb,恐怕不可能有这么快速度,别和我说让Innodb按期用导出xxx.sql机制备份,由于最小的一个数据库实例的数据量基本都是几十G大小。
四、从接触的应用逻辑来讲,select count(*) 和order by 是最频繁的,大概能占了整个sql总语句的60%以上的操做,而这种操做Innodb其实也是会锁表的,不少人觉得Innodb是行级锁,那个只是where对它主键是有效,非主键的都会锁全表的。
五、还有就是常常有不少应用部门须要我给他们按期某些表的数据,MyISAM的话很方便,只要发给他们对应那表的frm.MYD,MYI的文件,让他们本身在对应版本的数据库启动就行,而Innodb就须要导出xxx.sql了,由于光给别人文件,受字典数据文件的影响,对方是没法使用的。
六、若是和MyISAM比insert写操做的话,Innodb还达不到MyISAM的写性能,若是是针对基于索引的update操做,虽然MyISAM可能会逊色Innodb,可是那么高并发的写,从库可否追的上也是一个问题,还不如经过多实例分库分表架构来解决。
七、若是是用MyISAM的话,merge引擎能够大大加快应用部门的开发速度,他们只要对这个merge表作一些select count(*)操做,很是适合大项目总量约几亿的rows某一类型(如日志,调查统计)的业务表。
固然Innodb也不是绝对不用,用事务的项目就用Innodb的。另外,可能有人会说你MyISAM没法抗太多写操做,可是能够经过架构来弥补。
可使用mysql自带的日志表 mysql.general_log的记录 查询出存储过程的调用语句,执行。可使用debug也可以使用select语句进行跟踪调试
|
|
|
(1)语法
(2) 例子
|
(3)使用PREPARE 须要注意
① PREPARE stmt_name FROM preparable_stmt;预约义一个语句,并将它赋给 stmt_name ,tmt_name 是不区分大小写的。
② 即便 preparable_stmt 语句中的 ? 所表明的是一个字符串,你也不须要将 ? 用引号包含起来。
③ 若是新的 PREPARE 语句使用了一个已存在的 stmt_name ,那么原有的将被当即释放! 即便这个新的 PREPARE 语句由于错误而不能被正确执行。
④ PREPARE stmt_name 的做用域是当前客户端链接会话可见。
⑤ 要释放一个预约义语句的资源,可使用 DEALLOCATE PREPARE 句法。
⑥ EXECUTE stmt_name 句法中,若是 stmt_name 不存在,将会引起一个错误。
⑦ 若是在终止客户端链接会话时,没有显式地调用 DEALLOCATE PREPARE 句法释放资源,服务器端会本身动释放它。
⑧在预约义语句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。
⑨ PREPARE 语句不能够用于存储过程,自定义函数!但从 MySQL 5.0.13 开始,它能够被用于存储过程,仍不支持在函数中使用!
⑩ PREPARE 语句里的占位符参数值只能有用户变量提供,USING子句必须准确地指明用户变量,用户变量的数目与语句中的参数制造符的数量同样多。
|
|