Mysql存儲過程學習筆記css
經常使用的操做數據庫語言SQL語句在執行的時候須要要先編譯,而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。html
一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。前端
存儲過程一般有如下優勢:mysql
(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。sql
(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。數據庫
(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。express
(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。編程
(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。後端
存儲過程是數據庫存儲的一個重要的功能,可是MySQL在5.0之前並不支持存儲過程,這使得MySQL在應用上大打折扣。好在MySQL 5.0終於開始已經支持存儲過程,這樣便可以大大提升數據庫的處理速度,同時也能夠提升數據庫編程的靈活性。安全
(1). 格式
MySQL存儲過程建立的格式:CREATE PROCEDURE 過程名 ([過程參數[,...]])
[特性 ...] 過程體
|
這裏先舉個例子:
注:
(1)這裏須要注意的是DELIMITER //和DELIMITER ;兩句,DELIMITER是分割符的意思,由於MySQL默認以";"爲分隔符,若是咱們沒有聲明分割符,那麼編譯器會把存儲過程當成SQL語句進行處理,則存儲過程的編譯過程會報錯,因此要事先用DELIMITER關鍵字申明當前段分隔符,這樣MySQL纔會將";"當作存儲過程當中的代碼,不會執行這些代碼,用完了以後要把分隔符還原。
(2)存儲過程根據須要可能會有輸入、輸出、輸入輸出參數,這裏有一個輸出參數s,類型是int型,若是有多個參數用","分割開。
(3)過程體的開始與結束使用BEGIN與END進行標識。
這樣,咱們的一個MySQL存儲過程就完成了,是否是很容易呢?看不懂也不要緊,接下來,咱們詳細的講解。
MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT,形式如:
CREATE PROCEDURE([[IN |OUT |INOUT ] 參數名 數據類形...])
IN 輸入參數:表示該參數的值必須在調用存儲過程時指定,在存儲過程當中修改該參數的值不能被返回,爲默認值
OUT 輸出參數:該值可在存儲過程內部被改變,並可返回
INOUT 輸入輸出參數:調用時指定,而且可被改變和返回
小例子:
存儲過程爲:
|
|
調用存儲過程:
(1).變量定義:
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype爲MySQL的數據類型,如:int, float, date, varchar(length)
DECLARE l_int int unsigned default 4000000;
DECLARE l_numeric number(8,2) DEFAULT 9.95;
DECLARE l_date date DEFAULT '1999-12-31';
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
(2).變量賦值
SET 變量名 = 表達式值 [,variable_name = expression ...]
(3).變量做用域
內部的變量在其做用域範圍內享有更高的優先權,當執行到end。變量時,內部變量消失,此時已經在其做用域外,變量再也不可見了,應爲在存儲過程外不再能找到這個申明的變量,可是你能夠經過out參數或者將其值指派給會話變量來保存其值。
|
定義條件和處理程序是事先定義程序執行過程當中可能遇到的問題。而且能夠在處理程序中定義解決這些問題的辦法。這種方式能夠提早預測可能出現的問題,並提出解決辦法。這樣能夠加強程序處理問題的能力,避免程序異常中止。MySQL中都是經過DECLARE關鍵字來定義條件和處理程序。本小節中將詳細講解如何定義條件和處理程序。
(1).定義條件
MySQL中可使用DECLARE關鍵字來定義條件。其基本語法以下:
DECLARE condition_name CONDITION FOR condition_value
condition_value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code
其中,condition_name參數表示條件的名稱;condition_value參數表示條件的類型;sqlstate_value參數和mysql_error_code參數均可以表示MySQL的錯誤。例如ERROR 1146 (42S02)中,sqlstate_value值是42S02,mysql_error_code值是1146。
【示例】 下面定義"ERROR 1146 (42S02)"這個錯誤,名稱爲can_not_find。能夠用兩種不一樣的方法來定義,代碼以下:
//方法一:使用sqlstate_value
DECLARE can_not_find CONDITION FOR SQLSTATE '42S02' ;
//方法二:使用mysql_error_code
DECLARE can_not_find CONDITION FOR 1146 ;
(2).定義處理程序
MySQL中可使用DECLARE關鍵字來定義處理程序。其基本語法以下:
DECLARE handler_type HANDLER FOR
condition_value[,...] sp_statement
handler_type:
CONTINUE | EXIT | UNDO
condition_value:
SQLSTATE [VALUE] sqlstate_value |
condition_name | SQLWARNING
| NOT FOUND | SQLEXCEPTION | mysql_error_code
其中,handler_type參數指明錯誤的處理方式,該參數有3個取值。這3個取值分別是CONTINUE、EXIT和UNDO。CONTINUE表示遇到錯誤不進行處理,繼續向下執行;EXIT表示遇到錯誤後立刻退出;UNDO表示遇到錯誤後撤回以前的操做,MySQL中暫時還不支持這種處理方式。
注意:一般狀況下,執行過程當中遇到錯誤應該馬上中止執行下面的語句,而且撤回前面的操做。可是,MySQL中如今還不能支持UNDO操做。
所以,遇到錯誤時最好執行EXIT操做。若是事先可以預測錯誤類型,而且進行相應的處理,那麼能夠執行CONTINUE操做。
condition_value參數指明錯誤類型,該參數有6個取值。sqlstate_value和mysql_error_code與條件定義中的是同一個意思。
condition_name是DECLARE定義的條件名稱。SQLWARNING表示全部以01開頭的sqlstate_value值。NOT FOUND表示全部以02開頭的
sqlstate_value值。SQLEXCEPTION表示全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值。sp_statement表示一些存儲過程或函
數的執行語句。
【示例】 下面是定義處理程序的幾種方式。代碼以下:
//方法一:捕獲sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SET @info='CAN NOT FIND';
//方法二:捕獲mysql_error_code
DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';
//方法三:先定義條件,而後調用
DECLARE can_not_find CONDITION FOR 1146 ;
DECLARE CONTINUE HANDLER FOR can_not_find SET
@info='CAN NOT FIND';
//方法四:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
//方法五:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';
//方法六:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
上述代碼是6種定義處理程序的方法。
第一種方法是捕獲sqlstate_value值。若是遇到sqlstate_value值爲42S02,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。
第二種方法是捕獲mysql_error_code值。若是遇到mysql_error_code值爲1146,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。
第三種方法是先定義條件,而後再調用條件。這裏先定義can_not_find條件,遇到1146錯誤就執行CONTINUE操做。
第四種方法是使用SQLWARNING。SQLWARNING捕獲全部以01開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。
第五種方法是使用NOT FOUND。NOT FOUND捕獲全部以02開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"CAN NOT FIND"信息。
第六種方法是使用SQLEXCEPTION。SQLEXCEPTION捕獲全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。
咱們像知道一個數據庫下面有那些表,咱們通常採用show tables;進行查看。那麼咱們要查看某個數據庫下面的存儲過程,是否也能夠採用呢?答案是,咱們能夠查看某個數據庫下面的存儲過程,可是是令一鍾方式。
咱們能夠用
select name from mysql.proc where db=’數據庫名’;
或者
select routine_name from information_schema.routines where routine_schema='數據庫名';
或者
show procedure status where db='數據庫名';
進行查詢。
若是咱們想知道,某個存儲過程的詳細,那咱們又該怎麼作呢?是否是也能夠像操做表同樣用describe 表名進行查看呢?
答案是:咱們能夠查看存儲過程的詳細,可是須要用另外一種方法:
SHOW CREATE PROCEDURE 數據庫.存儲過程名;
就能夠查看當前存儲過程的詳細。
刪除一個存儲過程比較簡單,和刪除表同樣:DROP PROCEDURE從MySQL的表格中刪除一個或多個存儲過程。
|
(1). if-then -else語句
|
(2). case語句:
|
(1).WHILE...END WHILE
(2).
|
REPEAT...END REPEAT
(3).LOOP...END LOOP:
|
LOOP 循環不須要初始條件,這點和WHILE循環類似,同時和REPEAT循環同樣不須要結束條件,LEAVE 語句的意思是離開循環
(1).ITERATE:
經過引用符合語句的標號,來從新開始符合語句
|
|
(1).字符串類:
|
(2).數學類
|
(3).日期時間類
|
|
|
|
|
||
|
|
|
22. 學習prepare
|
|
右擊存儲過程---"Debug"--"Step Into", 以下圖
先擇"Stop Into"後,若是你的存儲過程有參數,則爲彈出窗體提示輸入參數值,若是沒有,則不直接運行;
存儲過程會從"begin"開始執行,而後點又上角的"step over"(F10), 單步執行。
查看變量值:選中變量,點右鍵,選擇"Add Wath", 這個變量就會在"Watches"這個視圖區出現,若是你單步運行到這個變量值,則能夠看見了,這樣就能夠調試,變量值是否正確,有錯誤沒,循環次數等。
(1) DECLARE…HANDLER語句
|
語法以下
a、condition_value [,condition_value],這個的話說明能夠包括多種狀況(方括弧表示可選的),也就是一個handler能夠定義成針對多種狀況進行相應的操做;另外condition_value能夠包括的值有上面列出來的6種:
一、mysql_error_code,這個表示MySQL的錯誤代碼,錯誤代碼是一個數字,完成是由mysql本身定義的,這個值能夠參考mysql數據庫錯誤代碼及信息。
二、SQLSTATE [VALUE] sqlstate_value,這個同錯誤代碼相似造成一一對應的關係,它是一個5個字符組成的字符串,關鍵的地方是它從ANSI SQL和ODBC這些標準中引用過來的,所以更加標準化,而不像上面的error_code徹底是mysql本身定義給本身用的,這個和第一個相似也能夠參考mysql數據庫錯誤代碼及信息。
三、condtion_name,這個是條件名稱,它使用DECLARE...CONDITION語句來定義,這個後面咱們會介紹如何定義本身的condition_name。
四、SQLWARNING,表示SQLTATE中的字符串以‘01’起始的那些錯誤,好比Error: 1311
SQLSTATE:01000
(ER_SP_UNINIT_VAR
)
五、NOT FOUND,表示SQLTATE中的字符串以‘02’起始的那些錯誤,好比Error: 1329
SQLSTATE: 02000
(ER_SP_FETCH_NO_DATA
),其實這個錯誤就是用在咱們介紹遊標的那個問題所出現的狀況,也就是沒有fetch到記錄,也就是咱們遊標到記錄的尾巴了的狀況。
六、SQLEXCEPTION,表示SQLSTATE中的字符串不是以'00'、'01'、'02' 起始的那些錯誤,這裏'00'起始的SQLSTATE其實表示的是成功執行而不是錯誤,另外兩個就是上面的4和5的兩種狀況。
上面的6種狀況其實能夠分爲兩類,一類就是比較明確的處理,就是對指定的錯誤狀況進行處理,包括一、二、3這三種方式;另外一類是對對應類型的錯誤的處理,就是對某一羣錯誤的處理,包括四、五、6這三種方式。這個是介紹了condition_value。另外還要注意的一個內容是MySQL在默認狀況下(也就是咱們沒有定義處理錯誤的方法-handler)本身的錯誤處理機制:一、對於SQLWARNING和NOT FOUND的處理方法就是無視錯誤繼續執行,因此在遊標的例子裏面若是咱們沒有對repeat的條件判斷的那個值作個no_more_products=1的handler來處理,那麼循環就會一直下去。二、對於SQLEXCEPTION的話,其默認的處理方法是在出現錯誤的地方就終止掉了。
b、statement,這個比較簡單就是當出現某種條件/錯誤時,咱們要執行的語句,能夠是簡單的如 SET var = value這樣的簡單的語句,也能夠是複雜的多行的語句,多行的話可使用BEGIN ..... END這裏把語句包括在裏面(這個比如delphi裏面的狀況,注意到咱們的存儲過程也是多行的,因此也要BEGIN .... END)。
c、handler_action,這個表示當執行完上面的statement後,但願執行怎樣的動做,這裏包括CONTINUE、EXIT、UNDO,表示繼續、退出、撤銷(暫時不支持)。這邊就是兩種動做,其實這兩種動做在上面也說過了,CONTINUE就是一個是SQLWARNING和NOT FOUND的默認處理方法,而EXIT就是SQLEXCEPTION的默認處理方法。
來看個簡單的例子,這裏建立一個對SQLSTATE的代碼爲'23000'的錯誤(重複的主鍵)進行處理的HANDLER,每次發生時咱們對變量@x進行增長1:
|
經過結果咱們知道出現了兩次插入的記錄同原有的記錄出現主鍵重複的狀況。固然這個是由下面這個代碼觸發的。
INSERT INTO products values(1,default,default,default,default,default);
(2) DECLARE...CONDITION語句
|
這個語句實際上是爲了讓咱們的錯誤條件更加的清晰明瞭化的,對於上面的狀況,像SQLSTATE '23000'這種表示是一種很不直觀的方法,要經過相應的文檔去對應,閱讀起來比較不方便。而DECLARE....CONDITION能夠對條件定義相對應的名稱,看個例子就清楚了:
固然在上面的例子咱們沒有用到BEGIN....END,咱們只有一行SET @x=@x+1;這裏咱們用duplicate_key這個條件名稱來對應到SQLSTATE '23000'上面,這樣查看起來更加的直觀。這你duplicate_key就是咱們上面介紹DECLARE....HANDLER時候的那個condition_name。
INSERT IGNORE INTO與INSERT INTO的區別就是INSERT IGNORE INTO會忽略數據庫中已經存在 的數據,若是數據庫沒有數據,就插入新的數據,若是有數據的話就跳過這條數據。這樣就能夠保留數據庫中已經存在數據,達到在間隙中插入數據的目的。
MyISAM 和InnoDB 講解
InnoDB和MyISAM是許多人在使用MySQL時最經常使用的兩個表類型,這兩個表類型各有優劣,視具體應用而定。基本的差異爲:MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快,可是不提供事務支持,而InnoDB提供事務支持以及外部鍵等高級數據庫功能。
如下是一些細節和具體實現的差異:
◆1.InnoDB不支持FULLTEXT類型的索引。
◆2.InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count(*)語句包含 where條件時,兩種表的操做是同樣的。
◆3.對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引。
◆4.DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。
◆5.LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。
另外,InnoDB表的行鎖也不是絕對的,假如在執行一個SQL語句時MySQL不能肯定要掃描的範圍,InnoDB表一樣會鎖全表,例如update table set num=1 where name like 「%aaa%」
兩種類型最主要的差異就是Innodb 支持事務處理與外鍵和行級鎖。而MyISAM不支持.因此MyISAM每每就容易被人認爲只適合在小項目中使用。
做爲使用MySQL的用戶角度出發,Innodb和MyISAM都是比較喜歡的,若是數據庫平臺要達到需求:99.9%的穩定性,方便的擴展性和高可用性來講的話,MyISAM絕對是首選。
緣由以下:
一、平臺上承載的大部分項目是讀多寫少的項目,而MyISAM的讀性能是比Innodb強很多的。
二、MyISAM的索引和數據是分開的,而且索引是有壓縮的,內存使用率就對應提升了很多。能加載更多索引,而Innodb是索引和數據是緊密捆綁的,沒有使用壓縮從而會形成Innodb比MyISAM體積龐大不小。
三、常常隔1,2個月就會發生應用開發人員不當心update一個表where寫的範圍不對,致使這個表無法正經常使用了,這個時候MyISAM的優越性就體現出來了,隨便從當天拷貝的壓縮包取出對應表的文件,隨便放到一個數據庫目錄下,而後dump成sql再導回到主庫,並把對應的binlog補上。若是是Innodb,恐怕不可能有這麼快速度,別和我說讓Innodb按期用導出xxx.sql機制備份,由於最小的一個數據庫實例的數據量基本都是幾十G大小。
四、從接觸的應用邏輯來講,select count(*) 和order by 是最頻繁的,大概能佔了整個sql總語句的60%以上的操做,而這種操做Innodb其實也是會鎖表的,不少人覺得Innodb是行級鎖,那個只是where對它主鍵是有效,非主鍵的都會鎖全表的。
五、還有就是常常有不少應用部門須要我給他們按期某些表的數據,MyISAM的話很方便,只要發給他們對應那表的frm.MYD,MYI的文件,讓他們本身在對應版本的數據庫啓動就行,而Innodb就須要導出xxx.sql了,由於光給別人文件,受字典數據文件的影響,對方是沒法使用的。
六、若是和MyISAM比insert寫操做的話,Innodb還達不到MyISAM的寫性能,若是是針對基於索引的update操做,雖然MyISAM可能會遜色Innodb,可是那麼高併發的寫,從庫可否追的上也是一個問題,還不如經過多實例分庫分表架構來解決。
七、若是是用MyISAM的話,merge引擎能夠大大加快應用部門的開發速度,他們只要對這個merge表作一些select count(*)操做,很是適合大項目總量約幾億的rows某一類型(如日誌,調查統計)的業務表。
固然Innodb也不是絕對不用,用事務的項目就用Innodb的。另外,可能有人會說你MyISAM沒法抗太多寫操做,可是能夠經過架構來彌補。
可使用mysql自帶的日誌表 mysql.general_log的記錄 查詢出存儲過程的調用語句,執行。可使用debug也可以使用select語句進行跟蹤調試
|
|
|
(1)語法
(2) 例子
|
(3)使用PREPARE 須要注意
① PREPARE stmt_name FROM preparable_stmt;預約義一個語句,並將它賦給 stmt_name ,tmt_name 是不區分大小寫的。
② 即便 preparable_stmt 語句中的 ? 所表明的是一個字符串,你也不須要將 ? 用引號包含起來。
③ 若是新的 PREPARE 語句使用了一個已存在的 stmt_name ,那麼原有的將被當即釋放! 即便這個新的 PREPARE 語句由於錯誤而不能被正確執行。
④ PREPARE stmt_name 的做用域是當前客戶端鏈接會話可見。
⑤ 要釋放一個預約義語句的資源,可使用 DEALLOCATE PREPARE 句法。
⑥ EXECUTE stmt_name 句法中,若是 stmt_name 不存在,將會引起一個錯誤。
⑦ 若是在終止客戶端鏈接會話時,沒有顯式地調用 DEALLOCATE PREPARE 句法釋放資源,服務器端會本身動釋放它。
⑧在預約義語句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。
⑨ PREPARE 語句不能夠用於存儲過程,自定義函數!但從 MySQL 5.0.13 開始,它能夠被用於存儲過程,仍不支持在函數中使用!
⑩ PREPARE 語句裏的佔位符參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量,用戶變量的數目與語句中的參數製造符的數量同樣多。
|
|