mysql储存过程

1.介绍

存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql。

 使用存储过程的优点:

#1. 用于替代程序写的SQL语句,实现程序与sql解耦

#2. 基于网络传输,传别名的数据量小,而直接传sql数据量大 

  使用存储过程的缺点:

#1. 程序员扩展功能不方便

2.程序与数据库结合使用方式

#方式一:
    MySQL:存储过程
    程序:调用存储过程

#方式二:
    MySQL:
    程序:纯SQL语句

#方式三:
    MySQL:
    程序:类和对象,即ORM(本质还是纯SQL语句)

3.创建简单储存过程(无参)

delimiter //
create procedure p1()
BEGIN
    select * from blog;
    INSERT into blog(name,sub_time) values("xxx",now());
END //
delimiter ;

#在mysql中调用
call p1(); #类似于MySQL的函数,但不是函数昂,别搞混了,MySQL的函数(count()max()min()等等)都是放在sql语句里面用的,不能单独的使用,存储过程是可以直接调用的  call 名字+括号;
#MySQL的视图啊触发器啊if判断啊等等都能在存储过程里面写,这是一大堆的sql的集合体,都可以综合到这里面
#在python中基于pymysql调用
cursor.callproc('p1') 
print(cursor.fetchall())

4.创建储存过程(有参)

对于存储过程,可以接收参数,其参数有三类:

#in          仅用于传入参数用
#out        仅用于返回值用
#inout     既可以传入又可以当作返回值

in:传入参数:

delimiter //
create procedure p2(
    in n1 int,  #n1参数是需要传入的,也就是接收外部数据的,并且这个数据必须是int类型
    in n2 int
)
BEGIN
    
    select * from blog where id > n1;  #直接应用变量
END //
delimiter ;
#调用存储过程的两种方式:或者说是两个地方吧
  #在mysql中调用
  call p2(3,2)

  #在python中基于pymysql调用
  cursor.callproc('p2',(3,2))
  print(cursor.fetchall())

  #通过存储过程的传参来看,也能体现出我们学习的Python的灵活性,传参不需要指定类型,也不需要声明这个参数是传入的还是返回出来的,参数既可以传入,这个参数也可以直接通过return返回。

  out:返回值:

#查看存储过程的一些信息:show create procedure p3; #查看视图啊、触发器啊都这么看,还可以用G,show create procedure p3G;G的意思是你直接查看表结构可能横向上显示不完,G是让表给你竖向显示,一row是一行的字段delimiter //
create procedure p3(
    in n1 int,
    out res int
)
BEGIN
    select * from blog where id > n1;  
    set res = 1;  #我在这里设置一个res=1,如果上面的所有sql语句全部正常执行了,那么这一句肯定也就执行了,那么此时res=1,如果我最开始传入的时候,给res的值设置的是0,#那么你想,最后我接收到的返回值如果是0,那么说明你中间肯定有一些sql语句执行失败了#注意写法:out的那个参数,可以用set来设置,set设置之后表示这个res可以作为返回值,并且不需要像python一样写一个return,你直接set之后的值,就是这个存储过程的返回值
END //
delimiter ;

#在mysql中调用
set @res=0; #这是MySQL中定义变量名的固定写法(set @变量名=值),可以自己规定好,0代表假(执行失败),1代表真(执行成功),如果这个被改为1了,说明存储过程中的sql语句执行成功了
call p3(3,@res);#注意:不要这样写:call p3(3,1),这样out的参数值你写死了,没法确定后面这个1是不是成功了,也就是说随后这个out的值可能改成0了,也就是失败了,但是这样你就判断不了了,你后面查看的这个res就成1了,所以这个参数应该是一个变量名昂,定义变量名就是上一句,如果你直接传一个常量数字,会报错的,写法不对。
select @res; #看一下这个结果,就知道这些sql语句是不是执行成功了,大家明白了吗~~~

#在python中基于pymysql调用,在python中只需要知道存储过程的名字就行了
cursor.callproc('p3',(3,0)) #0相当于set @res=0,为什么这里这个out参数可以写常数0啊,因为你用的pymysql,人家会帮你搞定,pymysql其实会帮你写成这样:第一个参数变量名:@_p3_0=3,第二个:@_p3_1=0,也就是pymysql会自动帮你对应上一个变量名,pymysql只是想让你写的时候更方便#沿着网络将存储过程名和参数发给了mysql服务端,比咱们发一堆的sql语句肯定要快对了,mysql帮你调用存储过程
print(cursor.fetchall()) #查询select的查询结果

cursor.execute('select @_p3_0,@_p3_1;') #@_p3_0代表第一个参数,@_p3_1代表第二个参数,即返回值
print(cursor.fetchall())#别忘了关掉:cursor.close()conn.close()#注意昂:存储过程在哪个库里面建的,就只能在哪个库里面用

  inout:既可传入又可以返回值:

delimiter //
create procedure p4(
    inout n1 int
)
BEGIN
    select * from blog where id > n1;
    set n1 = 1;
END //
delimiter ;

#在mysql中调用
set @x=3;
call p4(@x);
select @x;


#在python中基于pymysql调用
cursor.callproc('p4',(3,))
print(cursor.fetchall()) #查询select的查询结果

cursor.execute('select @_p4_0;') 
print(cursor.fetchall())

  存储过程结合事务来写:

delimiter //
            create procedure p4(
                out status int
            )
            BEGIN
                1. 声明如果出现异常则执行{
                    set status = 1;
                    rollback;
                }
                   
                开始事务
                    -- 由秦兵账户减去100
                    -- 方少伟账户加90
                    -- 张根账户加10
                    commit;
                结束
                
                set status = 2;
                
                
            END //
            delimiter ;

#实现
delimiter //
create PROCEDURE p5(
    OUT p_return_code tinyint
)
BEGIN 
    DECLARE exit handler for sqlexception   #声明如果一旦出现异常则执行下面的这个begin和end里面的操作
    BEGIN 
        -- ERROR   #--是什么啊,忘了吧,是注释的意思,就告诉你后面是对错误的处理
        set p_return_code = 1;  #将out返回值改为1了,这是你自己规定的,1表示出错了
        rollback;  #回滚事务
    END; 

    DECLARE exit handler for sqlwarning  #声明了出现警告信息之后你的操作行为
    BEGIN 
        -- WARNING 
        set p_return_code = 2; 
        rollback; 
    END; 

    START TRANSACTION;  #其实咱们这个存储过程里面就是执行这个事务,并且一直检测着这个事务,一旦出错或者出现警告,就rollback
        DELETE from tb1; #事务里面的任何一条sql执行失败或者执行出现警告,都会执行上面我们声明的那些对应的操作,如果没有任何的异常,就会自动执行下面的commit,并执行后面成功的sql
        insert into blog(name,sub_time) values('yyy',now());  #拿我的代码进行测试的时候,别忘了改成你自己库里的表,还有表里面对应的字段名要有的,自己测试的时候,可以自己写一个错误的sql来试试看
    COMMIT; 

    -- SUCCESS 
    set p_return_code = 0; #0代表执行成功

END //
delimiter ;

#在mysql中调用存储过程
set @res=123;
call p5(@res);
select @res;

#在python中基于pymysql调用存储过程
cursor.callproc('p5',(123,)) #注意后面这个参数是个元祖,别忘了逗号,按照我们上面规定的,上面有三个值0,1,2:0成功、1失败、2警告也是失败。所以我们传给这个out参数的值只要不是这三个值就行了,这里给的是100
print(cursor.fetchall()) #查询select的查询结果

cursor.execute('select @_p5_0;')
print(cursor.fetchall())#执行成功以后,查看一下结果就能看到执行后的值了

5.执行存储过程

  在MySQL中执行存储过程:

-- 无参数
call proc_name()

-- 有参数,全in
call proc_name(1,2)

-- 有参数,有in,out,inout
set @t1=0;
set @t2=3;
call proc_name(1,2,@t1,@t2)

执行存储过程

  在python中基于pymysql来执行存储过程:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行存储过程
cursor.callproc('p1', args=(1, 22, 3, 4))
# 获取执行完存储的参数
cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
result = cursor.fetchall()

#conn.commit()
cursor.close()
conn.close()


print(result)

6.除存储过程

drop procedure proc_name;
原文地址:https://www.cnblogs.com/zdqc/p/11498761.html