Mysql存儲過程mysql
存儲過程是保存在Mysql上的一個別名(就是一堆SQL語句),使用別名就能夠查到結果不用再去寫SQL語句。存儲過程用於替代程序員寫SQL語句。程序員
建立存儲過程sql
delimiter // CREATE PROCEDURE p1() BEGIN SELECT * FROM studenttable; INSERT INTO teachertable(tname) VALUES('陳晨'); END // delimiter ;
當咱們寫完這段代碼並執行,再去調用p1()就能夠直接執行裏面的查詢數據庫
call p1();
執行結果:oop
這樣的好處能讓功能代碼都整合到一塊且不用再去寫SQL語句,很差之處在於若是要改數據庫中的資料,那不必定能從存儲過程當中能拿到數據。性能
在公司處理數據時選用的方式:fetch
方式一:spa
Mysql(DBA):存儲過程3d
程序(程序員):調用存儲過程code
方式二:
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 ;
遊標
遊標的性能雖然不高可是能實現循環的效果,對於每一行數據要進行分開計算的時候咱們才須要用到遊標
先建立兩個表t二、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)