zoukankan      html  css  js  c++  java
  • 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;
    
  • 相关阅读:
    Linux内核中的jiffies 以及时间的获取time
    linux2.6内核启动流程简述
    qt 显示控件 导致频闪
    V4L2应用程序框架
    linux 目标机 windows 图形界面ftp登录
    linux2.4内核启动流程简述及2410主频修改
    块设备驱动编写总结一(ZT)
    backlight misc驱动范例 及应用程序范例
    如何通过结构中的某个成员地址获取结构本身的指针???
    我是怎么招聘程序员的
  • 原文地址:https://www.cnblogs.com/zdqc/p/11498761.html
Copyright © 2011-2022 走看看