Python學習日記(四十) Mysql資料庫篇 八
阿新 • • 發佈:2020-12-15
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)