zoukankan      html  css  js  c++  java
  • Python学习日记(四十) Mysql数据库篇 八

    Mysql存储过程

    存储过程是保存在Mysql上的一个别名(就是一堆SQL语句),使用别名就可以查到结果不用再去写SQL语句。存储过程用于替代程序员写SQL语句。

    创建存储过程

    delimiter //
    CREATE PROCEDURE p1()
    BEGIN
        SELECT * FROM studenttable;
        INSERT INTO teachertable(tname) VALUES('陈晨');
    END //
    delimiter ;

    当我们写完这段代码并执行,再去调用p1()就可以直接执行里面的查询

    call p1();

    执行结果:

    这样的好处能让功能代码都整合到一块且不用再去写SQL语句,不好之处在于如果要改数据库中的资料,那不一定能从存储过程中能拿到数据。

    在公司处理数据时选用的方式:

    方式一:

      Mysql(DBA):存储过程

      程序(程序员):调用存储过程

    方式二:

      Mysql:什么都不做

      程序:写SQL语句

    方式三:

      Mysql:什么都不做

      程序:类和对象(本质就是SQL语句 )

    通过Python中的pymysql模块拿到p1的数据:

    import pymysql
    conn = pymysql.connect(host = 'localhost',user = 'root',password = '',database = 'db2',charset = 'utf8')
    cursor = conn.cursor()
    cursor.callproc('p1')
    conn.commit()
    result = cursor.fetchall()
    print(result)
    cursor.close()
    conn.close()

    传参数in

    in表示传入一个值

    delimiter //
    CREATE PROCEDURE p2(
        IN pid INT,
        IN pnumber INT
    )
    BEGIN
        SELECT * FROM scoretable WHERE student_id > pid AND number > pnumber;
    END //
    delimiter ;

    呼叫执行过程p2并带入参数

    call p2(15,90);

    这样就能找到大于学生ID15并且分数大于90 的学生成绩

    利用pymysql执行达到相同效果:

    cursor.callproc('p2',(15,80))

    传参数out

    out伪造了一个返回值,主要用于表示存储过程的执行结果

    delimiter //
    create procedure p3(
        in pid int,
        out pnumber int
    )
    begin
        set pnumber = 80;
        select student_id from scoretable where student_id > pid and number > pnumber group by student_id;
    end //
    delimiter ;

    呼叫执行过程p3并带入参数

    set @pn = 80;
    call p3(20,@pn);
    select @pn;

    在pymysql中执行

    import pymysql
    conn = pymysql.connect(host = 'localhost',user = 'root',password = '',database = 'db2',charset = 'utf8')
    cursor = conn.cursor()
    
    cursor.callproc('p3',(15,80))
    r1 = cursor.fetchall()
    print(r1)
    
    cursor.execute('select @_p3_0,@_p3_1')     #返回前面写的这两个参数15 80
    r2 = cursor.fetchall()
    print(r2)
    
    cursor.close()
    conn.close()

    传参数inout

    结合in和out两种特性

    事务

    比方说双方进行一笔交易,但出现某种错误,一方支付了钱另一方没有收到,就可以通过事务回滚到最初的状态

    delimiter //
    create procedure p4(
        out p_status tinyint                                                     -- 状态变量,用于判断是否出现执行异常
    )
    begin 
        declare exit handler for sqlexception                             -- 执行出现异常的代码
        begin
            set p_status = 1;                                                     -- 1表示出现异常
            rollback;                                                                -- 将事务回滚
        end ;
        
        start transaction;                                                       -- 开始事务
            select student_id from scoretable group by student_id;
            insert into scoretable(student_id,course_id,number) values(25,3,78);
        commit;                                                                         -- 结束事务
        set p_status = 2;                                                               -- 2表示没有出现异常
    end //
    delimiter ;

    游标

    游标的性能虽然不高但是能实现循环的效果,对于每一行数据要进行分开计算的时候我们才需要用到游标

    先创建两个表t2、t3,然后实现t3中每行score的值等于每行t2中id+score的值

    t2:

    t3:

    存储过程代码:

    delimiter //
    create procedure p5()
    begin 
        declare p_id int;
        declare p_score int;
        declare done int default false;
        declare temp int;
        
        declare my_cursor cursor for select id,score from t2;
        declare continue handler for not found set done = true;
        
        open my_cursor;
            p_l:loop
                fetch my_cursor into p_id,p_score;
                if done then 
                    leave p_l;
                end if;
                set temp = p_id + p_score;
                insert into t3(score) values(temp);
            end loop p_l;
        close my_cursor;
    end //
    delimiter ;

    执行p5:

    call p5();

    结果:

    动态执行SQL(防SQL注入)

    delimiter // 
    create procedure p7(
        in arg int
    )
    -- 预检测SQL语句是否具有合法性
    begin 
        set @ppp = arg;
        prepare prod from 'select * from studenttable where sid > ?';
        execute prod using @ppp;
        deallocate prepare prod;
    end //
    delimiter ;
    call p7(15)
  • 相关阅读:
    NTP on FreeBSD 12.1
    Set proxy server on FreeBSD 12.1
    win32 disk imager使用后u盘容量恢复
    How to install Google Chrome Browser on Kali Linux
    Set NTP Service and timezone on Kali Linux
    Set static IP address and DNS on FreeBSD
    github博客标题显示不了可能是标题包含 特殊符号比如 : (冒号)
    server certificate verification failed. CAfile: none CRLfile: none
    删除文件和目录(彻底的)
    如何在Curl中使用Socks5代理
  • 原文地址:https://www.cnblogs.com/mtxcat/p/14136690.html
Copyright © 2011-2022 走看看