今天,需要对sohu邮箱用户的过期积分进行清理


过期的积分早已经计算好了,存放在mysql的一个表中


因此,清理的过程逻辑相对比较简单,就是update用户的可用积分,并保留此刻的可用积分作为历史记录


由于都是针对Mysql的操作,所以,就想用Mysql的存储过程来实现


N年之前,我在第一家公司里,曾写过无数的SQL SERVER的存储过程和触发器


MySql的Procedure一直没写过,不过,查了下Mysql的参考手册,还是比较简单的



折叠复制代码




  1. drop procedure if exists pro_ysz;    

  2.   

  3. delimiter //   

  4.   

  5. CREATE PROCEDURE pro_ysz(out rtn int)   

  6. BEGIN  

  7.   

  8.     DECLARE v_userid varchar(50);    

  9.     DECLARE v_totalscore int default 0;   

  10.     DECLARE v_freescore int default 0;   

  11.     DECLARE v_expirescore int default 0;   

  12.     DECLARE v_done int default 0;   

  13.   

  14.     DECLARE cur cursor for select userid,expirescore from ... where ... limit 0,10;   

  15.   

  16.     -- cursor end  

  17.     DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET v_done = 1;    

  18.     -- exception occur  

  19.     DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback;   

  20.   

  21.     SET rtn = 0;   

  22.   

  23.     open cur;      

  24.           

  25.     fetch cur into v_userid,v_expirescore;   

  26.        

  27.     while v_done = 0 do   

  28.   

  29.         select ...,... into v_totalscore,v_freescore from ... where ... = v_userid;   

  30.            

  31.         select v_userid,v_totalscore,v_freescore;   

  32.            

  33.         if v_freescore > v_expirescore then  

  34.             set v_freescore = v_freescore - v_expirescore;   

  35.         else  

  36.             set v_freescore = 0;   

  37.         end if;   

  38.   

  39.         insert into ... (...) values(v_userid,v_totalscore,v_freescore,now());   

  40.            

  41.  &nb
    sp;      
    update ... set ... = v_freescore where ... = v_userid;   

  42.         update ... set ... = 1 where ... = v_userid;   

  43.   

  44.         commit;   

  45.            

  46.         -- reset score  

  47.         set v_totalscore = 0;   

  48.         set v_freescore = 0;   

  49.         set rtn = rtn + 1;   

  50.   

  51.         fetch cur into v_userid,v_expirescore;   

  52.            

  53.     end while;   

  54.   

  55.     close cur;    

  56.   

  57.  END  

  58.   

  59. //   

  60.   

  61. delimiter ;  






其中,里面有几个要点:



  1. delimiter //,是设置Mysql statement的分隔符,默认是分号;,所以需要先修改成其它的符号,最后修改回去

  2. out rtn int,设置存储过程的返回参数,使用call pro_ysz(@rtn);调用后,可通过select @rtn;来查看返回值

  3. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET v_done = 1;当游标到末尾时,设置对应的变量,控制后续的循环

  4. DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback;设置执行中有异常时,rollback,并继续后续的执行

  5. select v_userid,v_totalscore,v_freescore;在存储过程中模拟print语句来调试,可以打印出对应的变量值


最后,由一个Shell来执行



折叠复制代码




  1. cdate=`date +%Y%m%d%H%M%S`   

  2. echo "$cdate Starting shell..."   

  3. while [ 1 -lt 2 ]   

  4. do   

  5.         mysql -e 'call pro_ysz(@rtn)' db   

  6.         sleep 5   

  7. done