MySQL写存储过程的坑点

本身需求很简单,但是因为之前都没有写过存储过程。所以很多坑点没踩过。

另外:阿里巴巴开发手册(三)MYSQL 7.【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

当业务主导时,就当没说。

大致需求是:传入几个参数当做查询条件,查询满足条件的 User,然后为 User 生成一批业务数据,主要是得到 User的主键 id。参数中有起始截止时间,在该区间内以天为单位,每天为每一位 User生成一条业务数据。最终语句是这样:
内容已做脱敏处理

show code

/*
 创建存储过程 AutoCreateData
 company_id   公司id
 dept_id      部门id
 start_day    起始时间
 end_day      截止时间
 ATTENTIONS:
 1.调用该过程,会覆盖式插入 t_business (user_id在该时间区间内的bizdata)
 */
 DELIMITER $$
 DROP PROCEDURE IF EXISTS AutoCreateData;
 CREATE PROCEDURE AutoCreateData(IN company_id VARCHAR(32),IN dept_id VARCHAR(32),IN start_day VARCHAR(10),IN end_day VARCHAR(10))
 BEGIN
     DECLARE user_id VARCHAR(32);
     DECLARE _STOP BOOLEAN DEFAULT FALSE;
     DECLARE start_day_date date;
     DECLARE end_day_date date;
      DECLARE user_cursor CURSOR FOR SELECT t.id FROM user t where t.company_id=company_id and t.dept_id=dept_id and t.status=0;
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET _STOP=TRUE;
     SET start_day_date=DATE_FORMAT(start_day,'%Y%m%d');
     SET end_day_date=DATE_FORMAT(end_day,'%Y%m%d');
     OPEN user_cursor;
     my_loop:LOOP
         --  每次循环为 user_id 重置start_day_date
         SET start_day_date=DATE_FORMAT(start_day,'%Y%m%d');
         FETCH user_cursor INTO user_id;
         IF _STOP  THEN 
             LEAVE my_loop;
         END IF;
         WHILE start_day_date <= end_day_date DO
             REPLACE INTO t_business
                 (id,company_id,user_id,pb_date,dept_id,create_date,create_uid)
             VALUE
                 (UUID(),
                  company_id,
                  user_id,
                  start_day_date,
                  dept_id,
                  NOW(),
                  'SYS_AUTO_INSERT_PRESSURE_TEST');
             SET start_day_date = DATE_ADD(start_day_date,INTERVAL 1 DAY);
         END WHILE;
     END LOOP my_loop;
     CLOSE user_cursor;
 END $$
 DELIMITER ;

call

CALL AutoCreateData('company_id','dept_id','2021-05-13','2021-05-23')

坑点一:创建格式

不要使用 create or replace PROCEDURE ,这种方式 Oracle是OK的。

坑点二:replace

在存储过程内部的业务代码中,insert 业务数据时,通常我们会先删掉之前的数据,另一种情况是:当业务表的某个字段有唯一索引时,后期会插入失败,必须先删除。观者可以试试这种方法:先delete再insert。保证你加班到明天。

请使用 replace into tableName() values() 替换。

坑点三:别名

在存储过程逻辑代码一开始,我们可能会使用某几个参数去查询一张表的数据。当在定义游标时,for之后的select语句中表名请使用别名,类似这样:

DECLARE user_cursor CURSOR FOR SELECT t.id FROM user t where t.company_id=company_id and t.dept_id=dept_id and t.status=0;

如果不用别名这种方式表示,可能会是这样的:

DECLARE user_cursor CURSOR FOR SELECT id FROM user where company_id=company_id and dept_id=dept_id and status=0;

仔细观察where条件语句,company_id=company_id,会不会懵逼,同样的mysql也可能懵逼,同时也不利于阅读。

坑点四:游标结束位置

在定义游标的结束标识 NOT FOUND SET _STOP=TRUE时,请紧跟游标的定义,中间不要插入其他的语句,否则游标取值时你会抓狂。

DECLARE user_cursor CURSOR FOR SELECT t.id FROM user t where t.company_id=company_id and t.dept_id=dept_id and t.status=0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _STOP=TRUE;

坑点五:结束符号

DELIMITER关键字的使用,在编写存储过程时,可能会有一大段语句,每句都需要使用英文分号作为结尾,MySQL在识别时就会断句,导致执行失败。解决方法是:使用DELIMITER重新定义MySQL默认的语句结束符 ,可以自定义这个符号,比如 $$ //

在编写完存储过程后,以自定义的符号结尾, 最后再次以 DELIMITER 重新定义语句结束符为英文分号。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值