mysql事务处理------存储过程和函数

mysql事务处理

存储过程和函数

存储程序可以分为存储过程和函数。在MySQL中,创建存储过程和函数使用的语句分别是CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句来调用存储过程,只能用输出变量返回值。函数可以从语句外调用(引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。

一句话解释存储过程/函数----------------就是提前将我们常用的一些查询存储起来,用的时候直接通过别名调用,非常的方便;

为什么要有存储过程/函数

当我们经常要查询某张表的信息的时候,不用每次都输入重复的代码,而是将该代码通过一点过方式存储起来,下次用的时候直接通过过程名调用即可;
使用存储过程将简化操作,减少冗余的操作步骤,同时,还可以减少操作过程中的失误,提高效率;

创建存储过程与调用存储过程

-- 格式----
delimiter ;;
create procedure  过程名([参数1,参数2,.......])
[存储过程特性]
begin -- 开始事务
过程内容
end ;; -- 结束事务
dilimiter ; -- 改回原来的结束符
-- 调用过程
call 过程名([参数1,参数2,....])
-- [] 内为可选内容


/*参数中的内容---- [in|out|inout] 参数名 参数类型
其中,IN表示输入参数,OUT表示输出参数,INOUT表示既可以输入也可以输出;param_name表示参数名称;type表示参数的类型,该类型可以是MySQL数据库中的任意类型*/

/* 存储过程/函数的特性---
● LANGUAGE SQL:说明routine_body部分是由SQL语句组成的,
当前系统支持的语言为SQL。SQL是LANGUAGE特性的唯一值。
● [NOT] DETERMINISTIC:指明存储过程执行的结果是否正确。
DETERMINISTIC表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。
NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为NOT DETERMINISTIC。
● { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIESSQL DATA }:指明子程序使用SQL语句的限制。CONTAINS SQL表明子程序包含SQL语句,但是不包含读写数据的语句;
NO SQL表明子程序不包含SQL语句;
READS SQL DATA说明子程序包含读数据的语句;
MODIFIES SQL DATA表明子程序包含写数据的语句。
默认情况下,系统会指定为CONTAINS SQL。
● SQL SECURITY { DEFINER | INVOKER }:指明谁有权限来执行。
DEFINER表示只有定义者才能执行。
INVOKER表示拥有权限的调用者可以执行。默认情况下,系统指定为DEFINER。
● COMMENT 'string':注释信息,可以用来描述存储过程或函数。
*/

例如以下操作---------------->>>>

-- 创建存储过程-----
mysql> delimiter /  -- 更改结束符
mysql> create procedure search() -- 此存储过程没有参数,但是后面的()仍然需要
    -> begin
    -> select * from emp ;
    -> end /
Query OK, 0 rows affected (0.04 sec)
mysql> delimiter ;  -- 改回原来的结束符
-- 调用存储过程


mysql>  call search();
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7367 | NULL   | NULL      | NULL | NULL       |    NULL |    NULL |     40 |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
15 rows in set (0.00 sec)

Query OK, 0 rows affected (0.10 sec)

练习------
– 查询当月应发的总薪资 ,因为每个月都要发,所以可以设置为过程

mysql> delimiter ;;
mysql> create procedure salaryAll(out param double)
    -> begin
    -> select sum(sal+ifnull(comm,0)) 当月应发总薪资 from emp;
    -> end ;;
Query OK, 0 rows affected (0.05 sec)
mysql> delimiter ;

mysql> call salaryall(@sal);-- 这里参数是一个变量,
+----------------+
| 当月应发总薪资 |
+----------------+
|       31225.00 |
+----------------+
1 row in set (0.02 sec)

mysql> call salaryall(@empno);----调用无关列,但是参数类型相同
+----------------+
| 当月应发总薪资 |
+----------------+
|       31225.00 |
+----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql> call salaryall(@ename);----调用无关列,但是参数类型不同
+----------------+
| 当月应发总薪资 |
+----------------+
|       31225.00 |
+----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
-- 可以发现只要输入任何参数符合数据即可求出当月应发薪资,所以有时候要对参数做一些限制;

创建存储函数与调用存储函数

-- 格式--
delimiter ;;
create function 函数名 ([参数1,参数2,......]) 
returns type 
[函数特性]
return 函数内容
;;

delimiter ;
 --调用
 select 存储函数名(参数....)

内容解析基本跟存储过程一样;

mysql> delimiter ;;
mysql> create function nameall()
    -> returns varchar(20)
       -> return ( select ename from emp where empno=7893)
    -> ;;
    -- 错误提示  没有函数特性来约束,
    --- 解决方式----
   -- 1,添加函数特性约束;
    -- 2 ,设置| log_bin_trust_function_creators 为ON状态
    
    
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

mysql> show variables like '%trust%';
    -> ;;
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF   |
+---------------------------------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> set global log_bin_trust_function_creators = 'on';
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;;
mysql> create  function test()
    -> returns varchar(20) -- 函数返回值类型
    -> return (select ename from emp where empno=7893)-- 执行的操作
    -> ;;
Query OK, 0 rows affected (0.03 sec)
-- 调用存储函数--
mysql> delimiter ;
mysql> select test();
+--------+
| test() |
+--------+
| NULL   |----创建存储函数时empno 值写错了
+--------+
1 row in set (0.02 sec)
-- 将表中king的empno数据改为7893,在执行
mysql> select test();
+--------+
| test() |
+--------+
| KING   |
+--------+
1 row in set (0.00 sec)
-- 这里强调一下为了安全建议不要开启log_bin_trust_function_creators ,而是为存储函数添加存储特性来解决上述ERROR 1418 (HY000):问题

添加函数存储特性----


mysql> set global log_bin_trust_function_creators = 'off';
Query OK, 0 rows affected (0.00 sec)
-- 创建存储函数
mysql> delimiter ;;
mysql> create function find()
    ->    returns varchar(20)
    ->   READS SQL DATA
    ->      return (select empno from emp where ename='KING' )
    ->      ;;
-- 调用
mysql> select find();
+--------+
| find() |
+--------+
| 7893   |
+--------+
1 row in set (0.00 sec)

如果在存储函数中的return语句跟returns返回值类型不一样,那么返回值会被强制准换为恰当的类型
如果函数返回值为varchar(20) 但是return返回的是一个整数,那么该整数会被转换成varchar类型;

举个例子----


mysql> delimiter ;;
mysql> create function find2()
    ->    returns varchar(2)
    ->   READS SQL DATA
    ->      return (select empno from emp where ename='KING' )
    ->      ;;
Query OK, 0 rows affected (0.03 sec)

mysql> delimiter ;
mysql> select find2();
ERROR 1406 (22001): Data too long for column 'find2()' at row 2

mysql> delimiter ;;
mysql> create function find5()
    ->    returns  int(2)
    ->   READS SQL DATA
    ->      return (select empno from emp where ename='KING' )
    ->      ;;
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> delimiter ;
mysql> select find5();
+---------+
| find5() |
+---------+
|    7893 |
+---------+
1 row in set (0.00 sec)


可以发现int被转换换成了字符串类型,由于长度要求为2个,所以会提示ERROR 1406 (22001):错误;但是如果为int类型的即使指定显示宽度也会将内容显示出来;

小结----

指定参数为IN、OUT或INOUT只对PROCEDURE是合法的。(FUNCTION中总是默认为IN参数)。RETURNS子句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。

变量的使用

变量可以在存储过程中声明并使用,这些变量的作用范围是在BEGIN…END程序中;

定义变量----

--语法格式--
declare 变量名 变量数据类型 [default 默认值];
-- 如果没有default 则默认为该数据类型的默认值--- int 为 0 字符串为 null,类似于java中的默认值;
-- 如果为同一类型的变量,则可以写在一起最后定义数据类型
declare a ,b c int;

-- 变量值除了可以被声明为一个常数外,还可以是一个表达式;

设置变量值

-- 格式----
set  变量名 =值
set a= 10,b=30; 
set c=a+b;

还可以将select 语句查询到的值赋值到变量上;

declare id int;
declare name varchar(8);
select empno ,ename  into id ,name  from emp where empno=7893;




上一篇:Mysql字符集(2)--mysql从入门到精通(二)


下一篇:MySQL主从复制与读写分离