MYSQL事务、触发器、存储过程详细讲解

时间:2018-09-12
本文章向大家介绍MYSQL开启事务、回滚事务、提交事务、新建触发器、查询触发器、删除触发器、修改触发器及存储过程的基本语法等,需要的朋友可以参考一下

  事务

  事务:一系列将要发生或正在发生的连续操作,旨在保证数据操作的完整性。在事务开启之后,所有的操作都会被临时存储到事务日志,事务日志只有在收到commit命令之后,才会将操作同步到数据表,其他任何情况都会清空事务日志,例如突然断开连接、收到rollback命令等。事务操作主要包括自动事务(默认的,前天是set autocommit = on / 1;),手动事务(前提是set autocommit = off / 0;)。

  手动事务基本模型:

  1.   开启事务:start transaction;
  2.   一顿操作:这里包括常见的表内数据操作,比如update,insert , delete等语句,这里也可以设置一些返回点,savepoint + 回滚点名称;
  3.   回滚事务:rollback to + 回滚点名称;
  4.   提交事务:commit;

  自动事务基本模型:

  1.   一顿操作:对,就是一顿操作

  事务特性

    • 原子性:Atomic,表示事务的整个操作是一个整体,是不可分割的,要么全部成功,要么全部失败;
    • 一致性:Consistency,表示事务操作的前后,数据表中的数据处于一致状态;
    • 隔离性:Isolation,表示不同的事务操作之间是相互隔离的,互不影响;
    • 持久性:Durability,表示事务一旦提交,将不可修改,永久性的改变数据表中的数据。

  锁机制以后会详细讲解

  

  触发器

   触发器:trigger,是指事先为某张表绑定一段代码,当表中的某些内容发生改变(增、删、改)的时候,系统会自动触发代码并执行。

  1.   新建触发器: create trigger + 触发器名称 + 触发器时间(before/after) + 事件类型(update/delete/instert) on 表名 for each row begin 一顿操作语句;  end ;这里一顿操作不能随意,出现数据集最好使用into来查询
  2.   查询触发器: show triggers [like "_kity%"][regexp 正在表达式];
  3.   删除触发器: drop trigger + 触发器名称;
  4.   修改触发器: 触发器不能修改,只能删除,同视图一样。

  存储过程

   存储过程简称过程,procedure,是一种用来处理数据(增删改)的方式。简单点,我们也可以将其理解为没有返回值的函数。

  存储过程好处:

  1. 有输入输出参数,可以声明变量,有if/else, case,while等控制语句,通过编写存储过程,可以实现复杂的逻辑功能;
  2. 函数的普遍特性:模块化,封装,代码复用;
  3. 速度快,只有首次执行需经过编译和优化步骤,后续被调用可以直接执行,省去以上步骤;

  可想而知,通过存储过程可以封装各种视图、触发器、事务等等,因此可以实现各种风骚操作,先介绍下存储过程的基本语法:

  • -- ----------------------------
    -- Procedure structure for `proc_adder`
    -- ----------------------------
    DROP PROCEDURE IF EXISTS `proc_adder`;
    DELIMITER $
    CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_adder`(IN a int, IN b int, OUT sum int)
    BEGIN
        #Routine body goes here...
    
        DECLARE c int;
        if a is null then set a = 0; 
        end if;
        if b is null then set b = 0;
        end if;
        set sum  = a + b;
    END
    $
    DELIMITER ;
    
    

    简而言之,格式为:CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体,其中需要注意:

    •   MySQL默认以";"为分隔符,如果没有声明分割符,则编译器会把存储过程当成SQL语句进行处理,因此编译过程会报错,所以要事先用“DELIMITER //”声明当前段分隔符,让编译器把两个"//"之间的内容当做存储过程的代码,不会执行这些代码;“DELIMITER ;”的意为把分隔符还原。

    •   存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT: IN参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回(输入),为默认值;OUT参数该值可在存储过程内部被改变,并可返回(输出);INOUT参数调用时指定,并且可被改变和返回。

    •   过程体的开始与结束使用BEGIN与END进行标识。

    •   参数也是具有想要的作用域,局部变量的修改并不会对全部变量有任何损失。

    •   有上面所说,变量还是有必要简要介绍下,这里再copy一张图,方便理解:

    •   这里列举下变量的常见封装函数,可方便即使调用
      ABS (number2 ) //绝对值
      BIN (decimal_number ) //十进制转二进制
      CEILING (number2 ) //向上取整
      CONV(number2,from_base,to_base) //进制转换
      FLOOR (number2 ) //向下取整
      FORMAT (number,decimal_places ) //保留小数位数
      HEX (DecimalNumber ) //转十六进制
      注:HEX()中可传入字符串,则返回其ASC-11码,如HEX('DEF')返回4142143
      也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
      LEAST (number , number2 [,..]) //求最小值
      MOD (numerator ,denominator ) //求余
      POWER (number ,power ) //求指数
      RAND([seed]) //随机数
      ROUND (number [,decimals ]) //四舍五入,decimals为小数位数] 注:返回类型并非均为整数
      数值
      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个字符,
      注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
      字符串
      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) //小时
      LAST_DAY(date) //date的月的最后日期
      MICROSECOND(datetime) //微秒
      MONTH(datetime) //月
      MINUTE(datetime) //分返回符号,正负或0
      SQRT(number2) //开平方
      日期
    •   存储过程中的变量语法:DECLARE 变量名1[,变量名2...] 数据类型 [默认值], 内部变量在其作用域范围内享有更高的优先权,当执行到end时,内部变量消失,不再可见了,在存储
      过程外再也找不到这个内部变量,但是可以通过out参数或者将其值指派给会话变量来保存其值。

    •   存储过程中的变量赋值:SET 变量名 = 变量值 [,变量名= 变量值 ...]。

    •   全局变量(用户变量)的设置:用户变量一般以@开头,同样是利用set赋值,比如set @var1 = "12";

    •   调用:用call和你过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数。

    •   存储过程控制语句:

      #条件语句IF-THEN-ELSE
      DROP PROCEDURE IF EXISTS proc3;
      DELIMITER //
      CREATE PROCEDURE proc3(IN parameter int)
        BEGIN
          DECLARE var int;
          SET var=parameter+1;
          IF var=0 THEN
            INSERT INTO t VALUES (17);
          END IF ;
          IF parameter=0 THEN
            UPDATE t SET s1=s1+1;
          ELSE
            UPDATE t SET s1=s1+2;
          END IF ;
        END ;
        //
      DELIMITER ;
      
      
      #CASE-WHEN-THEN-ELSE语句
      DELIMITER //
        CREATE PROCEDURE proc4 (IN parameter INT)
          BEGIN
            DECLARE var INT;
            SET var=parameter+1;
            CASE var
              WHEN 0 THEN
                INSERT INTO t VALUES (17);
              WHEN 1 THEN
                INSERT INTO t VALUES (18);
              ELSE
                INSERT INTO t VALUES (19);
            END CASE ;
          END ;
        //
      DELIMITER ;
      
      
      DELIMITER //
        CREATE PROCEDURE proc5()
          BEGIN
            DECLARE var INT;
            SET var=0;
            WHILE var<6 DO
              INSERT INTO t VALUES (var);
              SET var=var+1;
            END WHILE ;
          END;
        //
      DELIMITER ;
      
      
      DELIMITER //
        CREATE PROCEDURE proc6 ()
          BEGIN
            DECLARE v INT;
            SET v=0;
            REPEAT
              INSERT INTO t VALUES(v);
              SET v=v+1;
              UNTIL v>=5
            END REPEAT;
          END;
        //
      DELIMITER ;
      
      
      DELIMITER //
        CREATE PROCEDURE proc7 ()
          BEGIN
            DECLARE v INT;
            SET v=0;
            LOOP_LABLE:LOOP
              INSERT INTO t VALUES(v);
              SET v=v+1;
              IF v >=5 THEN
                LEAVE LOOP_LABLE;
              END IF;
            END LOOP;
          END;
        //
      DELIMITER ;
      
      
      #ITERATE
      DELIMITER //
        CREATE PROCEDURE proc8()
        BEGIN
          DECLARE v INT;
          SET v=0;
          LOOP_LABLE:LOOP
            IF v=3 THEN
              SET v=v+1;
              ITERATE LOOP_LABLE;
            END IF;
            INSERT INTO t VALUES(v);
            SET v=v+1;
            IF v>=5 THEN
              LEAVE LOOP_LABLE;
            END IF;
          END LOOP;
        END;
        //
      DELIMITER ;
      存储过程之流程
    •   查看存储过程:show procedure status + [like 'pattern'];

    •   删除存储过程:drop procedure + 过程名;

    •   游标:游标是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。这里列举三种游标循环进行数据处理的实例。

      CREATE  PROCEDURE getTotal()
      BEGIN  
          DECLARE total INT; 
          ##创建接收游标数据的变量  
          DECLARE sid INT;  
          DECLARE sname VARCHAR(10);  
          #创建总数变量  
          DECLARE sage INT;  
          #创建结束标志变量  
          DECLARE done INT DEFAULT false;  
          #创建游标  
          DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age>30;  
          #指定游标循环结束时的返回值  
          DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;  
          #设置初始值  
          SET sage = 0;  
          SET total=0;
          #打开游标  
          OPEN cur;  
          #开始循环游标里的数据  
          read_loop:loop  
          #根据游标当前指向的一条数据  
          FETCH cur INTO sid,sname,sage;  
          #判断游标的循环是否结束  
          IF done THEN  
              LEAVE read_loop;    #跳出游标循环  
          END IF;  
          #获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,  
          SET total = total + 1;  
          #结束游标循环  
          END LOOP;  
          #关闭游标  
          CLOSE cur;  
      
          #输出结果  
          SELECT total;  
      END
      
      
      CREATE  PROCEDURE getTotal()
      BEGIN  
          DECLARE total INT; 
          ##创建接收游标数据的变量  
          DECLARE sid INT;  
          DECLARE sname VARCHAR(10);  
          #创建总数变量  
          DECLARE sage INT;  
          #创建结束标志变量  
          DECLARE done INT DEFAULT false;  
          #创建游标  
          DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age>30;  
          #指定游标循环结束时的返回值  
          DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;   
          SET total = 0;  
          OPEN cur;  
          FETCH cur INTO sid, sname, sage;  
          WHILE(NOT done) 
          DO  
              SET total = total + 1;  
              FETCH cur INTO sid, sname, sage;  
          END WHILE;  
      
          CLOSE cur;  
          SELECT total;  
      END
      
      CREATE getTotal()
      BEGIN  
          DECLARE total INT; 
          ##创建接收游标数据的变量  
          DECLARE sid INT;  
          DECLARE sname VARCHAR(10);  
          #创建总数变量  
          DECLARE sage INT;  
          #创建结束标志变量  
          DECLARE done INT DEFAULT false;  
          #创建游标  
          DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age > 30;  
          #指定游标循环结束时的返回值  
          DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;   
          SET total = 0;  
          OPEN cur;  
          REPEAT  
          FETCH cur INTO sid, sname, sage;   
          IF NOT done THEN  
              SET total = total + 1;  
          END IF;  
          UNTIL done END REPEAT;  
          CLOSE cur;  
          SELECT total;  
      END
      存储过程之游标
    •   事件:事件是用来执行定时任务的一组SQL集,在时间到时会触发。以后会相信讲解