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)
  • 相关阅读:
    Spring 框架学习:BeanFactory 和 FactoryBean
    Spring框架学习二:通过简单的HelloWorld程序理解IoC
    Spring框架学习一:环境准备
    Java多线程:Condition条件
    Java多线程:公平锁和非公平锁
    Java多线程:AQS源码分析
    Java多线程:可重入锁RentrantLock
    Java多线程:Unsafe 类以及 CAS 函数
    Java多线程:AtomicIntegerFieldUpdater 原子更新字段类
    Java多线程:AtomicReference AtomicStampedReference AtomicMarkableReference 原子更新引用类型
  • 原文地址:https://www.cnblogs.com/mtxcat/p/14136690.html
Copyright © 2011-2022 走看看