mysql的存储过程、事务、游标详解
mysql的存储过程、游标 、事务实例详解
下面是自己曾经编写过的mysql数据库存储过程,留作存档,以后用到的时候拿来参考。
其中,涉及到了存储过程、游标(双层循环)、事务。
【说明】:代码中的注释只针对当时业务而言,无须理会。
代码如下:
DELIMITER $$
DROP PROCEDURE IF EXISTS `transferEmailTempData`$$
CREATE PROCEDURE transferEmailTempData(IN jobId VARCHAR(24))
BEGIN
DECLARE idval VARCHAR(24) DEFAULT '';
DECLARE taskIdval VARCHAR(24) DEFAULT '';
DECLARE groupIdval VARCHAR(24) DEFAULT '';
DECLARE emailval VARCHAR(50) DEFAULT '';
/*标识正式表是否存在一条相同数据,即:groupId、email相同*/
DECLARE infoId VARCHAR(24) DEFAULT '';
/*标识事务错误*/
DECLARE err INT DEFAULT 0;
/*达到一定数量就进行提交,计数器*/
DECLARE counts INT DEFAULT 0;
/*标识是否回滚过*/
DECLARE isrollback INT DEFAULT 0;
/*游标遍历时,作为判断是否遍历完全部记录的标记*/
DECLARE done INTEGER DEFAULT 0;
/*获取临时表该任务的数据*/
DECLARE cur CURSOR FOR SELECT id,taskId,groupId,email FROM `t_email_data_temp` WHERE taskId=jobId;
/*根据群组id、email查询是否存在相同记录*/
DECLARE cur2 CURSOR FOR SELECT id FROM `t_email_info` e WHERE e.`group_id` = groupIdval AND e.`email_address` = emailval;
/* 出现错误,设置为1,只要发生异常就回滚*/
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET err=1;
/*声明当游标遍历完全部记录后将标志变量置成某个值*/
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET done=1;
/*开启事务*/
START TRANSACTION;
/*打开游标*/
OPEN cur;
/*使用LOOP循环遍历*/
out_loop:LOOP
/*将每一条结果对应的字段值赋值给变量*/
FETCH cur INTO idval,taskIdval,groupIdval,emailval;
IF done = 1 THEN
LEAVE out_loop;
END IF;
/*打开第二个游标*/
OPEN cur2;
SET done = 0;
FETCH cur2 INTO infoId;
/*如果正式表不存在相同groupId and email记录,添加到正式表*/
IF done = 1 THEN
/*插入正式表*/
INSERT INTO `t_email_info` VALUES(idval,emailval,groupIdval,0,'',NOW(),'admin',NOW(),'admin');
/*删除临时数据*/
DELETE FROM `t_email_data_temp` WHERE id = idval;
/*计数器,每1000条才提交*/
SET counts = counts + 1;
/*发生异常,回滚*/
IF err=1 THEN
SET isrollback=1;
ROLLBACK;
ELSE
IF counts = 1000 THEN
COMMIT;
/*达到1000条提交后,重置计数器*/
SET counts=0;
END IF;
END IF;
ELSE
/*已经存在相同记录,则删除该记录*/
IF done=0 THEN
DELETE FROM `t_email_data_temp` WHERE id = idval;
END IF;
END IF;
FETCH cur2 INTO infoId;
CLOSE cur2;
/*控制外部的循环,该步骤不能缺少,否则只循环一次就结束了*/
SET done=0;
END LOOP out_loop;
CLOSE cur;
/*如果没有发生过回滚事件,则更新task状态*/
/*如果回滚过,不更新task状态,下次执行任务的时候,会再次将剩余没有提交的数据进行添加到正式表*/
IF isrollback=0 THEN
UPDATE `t_email_task` t SET t.`if_finish` = 1 WHERE t.`id`=jobId;
END IF;
END$$
DELIMITER ;
窥探mysql存储过程细节
存储过程,可以这样认为,将我们需要特殊处理的sql语句封装成函数,当需要的时候我们只需调用这个函数就可以实现我们想要的操作,这个过程我们可以称之为存储过程。当然了,真正存储过程的定义不是这样的。但是我们可以这样简单的去理解存储过程。
下面我们看一个简单的使用存储过程的例子。
首先我们新建一张表 proced:
create table proced(
id int(5) primary key auto_increment,
name varchar(50),
type varchar(50)
);
然后我们需要向这个表中插入10万条数据,这个时候我们需要借助存储过程来实现这一功能。
mysql> delimiter //
mysql> create procedure adddata()
-->begin
-->declare n int default 0;
-->while n<100000
-->do
-->insert into proced(name,type) values(‘迹忆博客','onmpw');
-->set n = n+1;
-->end while;
-->end
-->//
mysql> delimiter ;
mysql> call adddata();
使用上述存储过程,我们就可以向proced表中插入10万条数据了。
借助上述小例子,我们来讲一下如何创建一个存储过程。
创建存储过程
首先我们来看一下创建存储过程的语法:
CREATE PROCEDURE procedure_name(IN/OUT/INOUT parameter TYPE)
BEGIN
procedure_body
END
这个过程比较简单。
在上面的小例子中我们看到在创建存储过程之前使用了delimiter //;,创建完成之后又再次 使用了命令 delimiter ;。
delimiter 是界定符,我们知道,在mysql命令行客户端,是通过分号(;)来界定一个命令是否完成的。在存储过程中,我们会多次使用到分号,但是这并不代表命令的结束,所以说我们需要使用delimiter命令来改变这个界定符。
mysql> delimiter //; 改变界定符为 //
mysql> delimiter ; 重新改变界定符为分号
所以说我们如果使用mysql命令行创建存储过程的话,我们必须在创建存储过程之前使用上述命令改变界定符。
接下来我们看到procedure_name()中的IN/OUT/INOUT,这是代表什么意思呢?
一个IN类型的参数会传递一个值到存储哦过程中,也就是我们在编程语言中自定义函数的参数。如果参数前面没有指定是IN/OUT/INOUT,那默认会是IN,看下面的例子:
mysql>delimiter //
mysql> create procedure in_proced(IN param VARCHAR(100))
-->begin
-->insert into proced(name,type) values(param,'onmpw');
-->end
-->//
mysql>delimiter ;
mysql> call in_proced(‘onmpw.com');
这就是在参数前指定IN的含义。
下面我们看OUT,指定为OUT的参数将从存储过程中传递一个值给调用者,也就是说,OUT可以认为这个参数就是我们自定义函数中的返回值。
mysql> delimiter //
mysql> create procedure out_proced(OUT param INT)
-->begin
-->select count(*) into param from proced;
-->end
-->//
mysql>delimiter ;
mysql> call out_proced(@a);
mysql>select @a;
+------+
| @a |
+------+
| 3 |
+------+
最后就是INOUT,很明显INOUT指定的参数被调用者初始化,其值在存储过程中可以被修改,并且任何改变对于调用者来说都是可见的。
看下面的例子:
mysql> delimiter //
mysql> create procedure inout_proced(INOUT param INT)
--> begin
--> select count(*) into param from proced where id>param;
--> end
-->//
mysql>delimiter ;
mysql>set @a = 3;
mysql>call inout_proced(@a);
mysql>select @a; 查看变量的值是否改变
以上就是创建一个简单的存储过程的方式。
删除存储过程
删除存储过程的语法:
DROP PROCEDURE IF EXISTS procedure_name
下面是使用实例:
mysql>drop procedure if exists proced;
修改存储过程
存储过程的修改时不能改变存储过程内的sql语句的,只能改变其属性,其语法如下:
ALTER PROCEDURE proc_name [characteristic ...]
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
总结:无论是删除存储过程还是修改存储过程,必须保证你要修改或者删除存储过程没有被其他存储过程使用,例如你有存储过程A,和存储过程B。A在B中被使用,如果我们想修改A或者删除A,必须确保B中不再使用A,否则如果我们删除A以后,再调用B的时候就会报错。
举个例子:
mysql>delimiter //
mysql>create procedure A(IN pa1 INT,OUT pa2 INT)
-->begin
-->select count(*) into pa2 from proced where id>pa1;
-->end
-->//
mysql>create procedure B(INOUT pa INT)
-->begin
-->declare v int;
-->call A(pa,v);
-->set pa = v;
-->end
-->//
mysql>delimiter ;
mysql>drop procedure A;
mysql>set @a=5;
mysql>call B(@a);
ERROR 1305 (42000): PROCEDURE test.A does not exists
以上就是对存储过程简单的介绍,希望对大家学习mysql存储过程有所帮助。
以上就是本次给大家分享的关于java的全部知识点内容总结,大家还可以在下方相关文章里找到相关文章进一步学习,感谢大家的阅读和支持。