三十、存储过程和事件调度

一、概念

存储过程,我的理解是写一段面向过程的包含sql的代码,然后编译存储到数据库。

之后再用时可以在数据库里直接执行,也可以通过事件来规律地重复调用,还可以在java等中进行调用。

二、基本语法

1.创建和删除

create proc[edure]  存储过程名([[IN |OUT |INOUT ] 参数名 数据类形...])

[区块名:]  begin
.........
end  [区块名]

drop  proc[edure]  if  exists   存储过程名

2.变量定义和赋值


变量定义                 declare   变量名  类型   [default  默认值];

直接赋值                  set    变量名 = 表达式;

查询赋值                  select  运算值[,...]   into  变量名[,...]  from  表名  [where  表达式];

3.语句

(1)条件语句


if   条件  then
.........
else
.........
end if;

(2)循环语句


(1).相当于java的while循环
WHILE  表达式  DO

.........

END WHILE ;


(2).相当于java的for循环
 LOOP

.........

END LOOP;


(3).相当于java的do..while循环

 REPEAT

.........

UNTIL  表达式

END REPEAT ;

4.游标

我的理解游标是对一个数据集的操作,这个数据集主要可以用于循环的判断,这个集合中的值可以顺次的与其他值做比较判断。游标的作用类似于指针或者数组下标。

declare  游标名 cursor  [local|global]  [forward_only|scroll]    for    select查询语句

 实例:
drop procedure mig_page_visit_often;
DELIMITER $$
CREATE PROCEDURE mig_page_visit_often()
BEGIN
DECLARE done INT DEFAULT 0; 
DECLARE v_ip varchar(50);
DECLARE v_inWhite int(6);
DECLARE v_haveSend int(6);
DECLARE v_cnt int(6);
DECLARE cur CURSOR FOR select ip,count from ip_access where time>=current_date;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; 
OPEN cur; 
REPEAT FETCH cur INTO v_ip,v_cnt;
IF NOT done THEN 
select count(1) into v_inWhite from ip_white where ip=v_ip;
if v_inWhite=0 then
select count(1) into v_haveSend from ip_sms_log where ip=v_ip and time>=current_date;
if v_haveSend=0 then
insert into ip_sms_log(ip,count,time) values (v_ip, v_cnt,now());
end if;
end if;
END IF; 
UNTIL done
END REPEAT; 
CLOSE cur; 
END
$$

 
说明:
(1)DECLARE done INT DEFAULT 0;这个用于处理游标到达最后一行的情况
(2)DECLARE cur1 CURSOR FOR select distinct(ip) from ip_access where time>=current_date;声明游标
(3) DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;声明游标的异常处理,设置一个终止标记
(4)   OPEN cur1; 打开游标
        当我们刚刚打开一个游标时,它并不指向第一条记录,而是指向第一条记录的前边。以书做个形象的比喻,游标不仅可以只想记录集中的每条记录(书内容呢每一页),也可以指向记录集外部没有记录的地方(书的封面或封底)。@@fetch_status有三种取值:0表示fetch正常执行、-1表示fetch超出了结果集、-2表示fetch所指向的行已经不存在了。
(5)   FETCH cur1 INTO v_ip;读取一行数据到变量

        fetch  next  from  游标名  into  变量名列表;是固定形式的读取下一个游标位置的数据的方法。当查询语句选择了多个字段的时候,读取时就需要向多个变量赋值。

        当开启了scroll(可在行之间来回跳跃)选项后,fetch可以用于读取next后移、prior前移、first第一行、last最后一行、absolute以数值定位到绝对行、relative以数值定位到相对行。
(6)   UNTIL done判断是否游标已经到达了最后
 
(7)   CLOSE cur1;关闭游标
(8) COMMIT;运行没有异常,提交事务
(9)可使用begin, end在发生异常时执行多个命令,如可将DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;改成
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'  begin  SET done = 1 end;
(10)游标使用顺序的总结:声明游标, 打开游标,从游标里读取,关闭游标。

(11)DECLARE {EXIT|CONTINUE} HANDLER FOR {error_number|{SQLSTATE error-string}|condition} SQL Statement;

           MYSQL允许两种错误处理器(也就是当一段程序出错后自动触发的代码),一种是exit处理,另外一种是 continue处理。 DECLARE EXIT HANDLER是用来处理异常的,意思是如果错误发生,程序接下来会做的操作。与exit不同的是,在CONTINUE处理执行后,原主程序仍然继续运行。

 

5.说明

(1)DELIMITER分隔符:

mysql> DELIMITER // 
mysql> CREATE PROCEDURE proc1(OUT s int) 
    -> BEGIN
    -> SELECT COUNT(*) INTO s FROM user; 
    -> END
    -> // 
mysql> DELIMITER ;
 
注:这里需要注意的是DELIMITER //和DELIMITER ;两句,DELIMITER是分割符的意思,因为MySQL默认以";"为分隔符,如果我们没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错,所以要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";"当做存储过程中的代码,不会执行这些代码,用完了之后要把分隔符还原。


(2)参数

参数共有三种参数类型,IN,OUT,INOUT,形式如:

CREATE PROCEDURE([[IN |OUT |INOUT ] 参数名 数据类形...])

IN 输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值

OUT 输出参数:该值可在存储过程内部被改变,并可返回

INOUT 输入输出参数:调用时指定,并且可被改变和返回


(3)MySQL存储过程的基本函数

(1).字符串类

CHARSET(str) //返回字串字符集
CONCAT (string2 [,... ]) //连接字串
INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0
LCASE (string2 ) //转换成小写
LEFT (string2 ,length ) //从string2中的左边起取length个字符
LENGTH (string ) //string长度
LOAD_FILE (file_name ) //从文件读取内容
LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定开始位置
LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length
LTRIM (string2 ) //去除前端空格
REPEAT (string2 ,count ) //重复count次
REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str
RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length
RTRIM (string2 ) //去除后端空格
STRCMP (string1 ,string2 ) //逐字符比较两字串大小
SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符

TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符
UCASE (string2 ) //转换成大写
RIGHT(string2,length) //取string2最后length个字符
SPACE(count) //生成count个空格

(2).数学类

ABS (number2 ) //绝对值
BIN (decimal_number ) //十进制转二进制
CEILING (number2 ) //向上取整
CONV(number2,from_base,to_base) //进制转换
FLOOR (number2 ) //向下取整
FORMAT (number,decimal_places ) //保留小数位数
HEX (DecimalNumber ) //转十六进制
LEAST (number , number2 [,..]) //求最小值
MOD (numerator ,denominator ) //求余
POWER (number ,power ) //求指数
RAND([seed]) //随机数
ROUND (number [,decimals ]) //四舍五入,decimals为小数位数

(3).日期时间类

ADDTIME (date2 ,time_interval ) //将time_interval加到date2
CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区
CURRENT_DATE ( ) //当前日期
CURRENT_TIME ( ) //当前时间
CURRENT_TIMESTAMP ( ) //当前时间戳
DATE (datetime ) //返回datetime的日期部分
DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间
DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime
DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间
DATEDIFF (date1 ,date2 ) //两个日期差
DAY (date ) //返回日期的天
DAYNAME (date ) //英文星期
DAYOFWEEK (date ) //星期(1-7) ,1为星期天
DAYOFYEAR (date ) //一年中的第几天
EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分
MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串
MAKETIME (hour ,minute ,second ) //生成时间串
MONTHNAME (date ) //英文月份名
NOW ( ) //当前时间
SEC_TO_TIME (seconds ) //秒数转成时间
STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示
TIMEDIFF (datetime1 ,datetime2 ) //两个时间差
TIME_TO_SEC (time ) //时间转秒数]
WEEK (date_time [,start_of_week ]) //第几周
YEAR (datetime ) //年份
DAYOFMONTH(datetime) //月的第几天
HOUR(datetime) //小时


三、存储过程的调用

1. 直接调用

call  存储过程名();


2. 事件调用

创建mysql事件。

如每5分钟调用一次上面的存储过程:

CREATE EVENT e_call_proc
    ON SCHEDULE
      EVERY 5 MINUTE
    DO CALL mig_page_visit_often();


3. java中调用

例如下面新建一个存储过程:

下面是java调用mysql存储过程的方法:

import java.sql.callablestatement;
import java.sql.connection;
import java.sql.drivermanager;
import java.sql.sqlexception;
import java.sql.types;
public class sqlutils {
    string url = "jdbc:mysql://127.0.0.1:3306/userinfo";
    string username = "root";
    string password = "password";
    public connection getconnection() {
        connection con=null;
        try{
            drivermanager.registerdriver(new com.mysql.jdbc.driver());
            con = drivermanager.getconnection(url, this.username, this.password);
        }catch(sqlexception sw){
         }
        return con;
    }
    public void testproc(){
        connection conn = getconnection();
        callablestatement stmt = null;
        try{
            stmt = conn.preparecall("{call mappingproc(?)}");   
            stmt.registeroutparameter(1, types.integer);
            stmt.execute();
            int i= stmt.getint(1);
            system.out.println("count = " + i);
        }catch(exception e){
            system.out.println("hahad = "+e.tostring());
        }finally{
            try {
                stmt.close();
                conn.close();
            }catch (exception ex) {
                system.out.println("ex : "+ ex.getmessage());
            }
        }
    }
    public static void main(string[] args) {
        new sqlutils().testproc();
    }
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值