摘要: 本篇博客僅做爲筆記,若有侵權,請聯繫,當即刪除(網上找博客學習,而後手記筆記,因紙質筆記不便保存,因此保存到網絡筆記)。數據庫
本文將介紹什麼是存儲過程,爲何要使用存儲過程以及如何使用存儲過程,而且介紹建立和使用存儲過程的基本語法。安全
1、存儲過程服務器
注意:須要MySQL 5 MySQL 5添加了對存儲過程的支持,所以,本章內容適用於MySQL 5及之後的版本。網絡
迄今爲止,使用的大多數SQL語句都是針對一個或多個表的單條語句。並不是全部操做都這麼簡單,常常會有一個完整的操做須要多條語句才能完成。例如,考慮如下的情形。函數
(1)爲了處理訂單,須要覈對以保證庫存中有相應的物品。性能
(2)若是庫存有物品,這些物品須要預約以便不將它們再賣給別人。學習
(3)庫存中沒有的物品須要訂購,這須要與供應商進行某種交互。測試
(4)關於哪些物品入庫(而且能夠當即發貨)和那些物品退訂,須要通知相應的客戶。this
這顯然不是一個完整的例子,它甚至超出了本書中所用樣例表的範圍,但足以幫助表達咱們的意思了。執行這個處理須要針對許多表的多條MySQL語句。此外,須要執行的具體語句以及其次序也不是固定的,它們可能會(和將)根據哪些物品在庫存中哪些不在而變化。spa
那麼,怎麼編寫此代碼?能夠單獨編寫每條語句,並根據結果有條件地執行另外的語句。在每次須要這個處理時(以及每一個須要它的應用中)都必須作這些工做。
能夠建立存儲過程。存儲過程簡單來講,就是爲之後的使用而保存的一條或多條MySQL語句的集合。可將其視爲批文件,雖然它們的做用不只限於批處理。
2、爲何要使用存儲過程
既然咱們知道了什麼是存儲過程,那麼爲何要使用它們呢?有許多理由,下面列出一些主要的理由。
(1)經過把處理封裝在容易使用的單元中,簡化複雜的操做(正如前面例子所述)。
(2)因爲不要求反覆創建一系列處理步驟,這保證了數據的完整性。若是全部開發人員和應用程序都使用同一(試驗和測試)存儲過程,則所使用的代碼都是相同的。
這一點的延伸就是防止錯誤。須要執行的步驟越多,出錯的可能性就越大。防止錯誤保證了數據的一致性。
(3)簡化對變更的管理。若是表名、列名或業務邏輯(或別的內容)有變化,只須要更改存儲過程的代碼。使用它的人員甚至不須要知道這些變化。
這一點的延伸就是安全性。經過存儲過程限制對基礎數據的訪問減小了數據錯誤(無心識的或別的緣由所致使的數據錯誤)的機會。
(4)提升性能。由於使用存儲過程比使用單獨的SQL語句要快。
(5)存在一些職能用在單個請求中的MySQL元素和特性,存儲過程可使用它們來編寫功能更強更靈活的代碼(後面博客能夠看到)。
換句話說,使用存儲過程有3個主要的好處,即簡單、安全、高性能。顯然它們都很重要。不過,在SQL代碼轉換爲存儲過程前,也必須知道它的一些缺陷。
(6)通常來講,存儲過程的編寫比基本SQL語句複雜,編寫存儲過程須要更高的技能,更豐富的經驗。
(7)你可能沒有建立存儲過程的安全訪問權限。許多數據庫管理員限制存儲過程的建立權限,容許用戶使用存儲過程,但不容許他們建立存儲過程。
儘管有些缺陷,存儲過程仍是很是有用的,而且應該儘量地使用。
注意:不能編寫存儲過程?你依然可使用 MySQL將編寫存儲過程的安全和訪問與執行存儲過程的安全和訪問區分開來。這是好事情,即便你不能(或不想)編寫本身的存儲過程,也仍然能夠在適當的時候執行別的存儲過程。
3、使用存儲過程
使用存儲過程須要知道如何執行(運行)它們。存儲過程的執行遠比其定義更常常遇到,所以,咱們將從執行存儲過程開始介紹。而後再介紹建立和使用存儲過程。
一、執行存儲過程
MySQL稱存儲過程的執行爲調用,所以MySQL執行存儲過程的語句爲CALL。CALL接收存儲過程的名字以及須要傳遞存儲過程的名字以及須要傳遞給它的任意參數。請看如下例子:
CALL productpricing(@pricelow, @pricehigh, @priceaverage);
分析:其中,執行名爲productpricing的存儲過程,它計算並返回產品的最低、最高和平均價格。
存儲過程能夠顯示結果,也能夠不顯示結果,後面再詳細介紹。
二、建立存儲過程
正如所述,編寫存儲過程並非微不足道的事情。爲讓你瞭解這個過程,請看一個例子--一個返回產品平均價格的存儲過程。如下是其代碼:
CREATE PROCEDURE productpricing() BEGIN SELECT Avg(prod_price) AS priceaverage FROM products; END;
分析:咱們稍後介紹第一條和最後一條語句。此存儲過程名爲productpricing,用CREATE PROCEDURE productpricing()語句定義。若是存儲過程接受參數,它們將在()中列舉出來。此存儲過程沒有參數,但後跟的()仍然須要。BEGIN和END語句用來限定存儲過程體,過程體自己僅是一個簡單的SELECT語句(使用前面講過的Avg()函數)。
在MySQL處理這段代碼時,它建立一個新的存儲過程product-pricing。沒有返回數據,由於這段代碼並未調用存儲過程,這裏只是爲之後使用而建立它。
注意:MySQL命令行客戶機的分割符 若是你使用的是MySQL命令行實用程序,應該仔細閱讀此說明。
默認的MySQL語句分隔符爲;。MySQL命令行實用程序也使用;做爲語句分隔符。若是命令行實用程序要解釋存儲過程自身內的;字符,則它們最終不會成爲存儲過程的成分,這會使存儲過程當中的SQL出現句法錯誤。
解決辦法是臨時更改命令行使用程序的語句分隔符,以下所示:
DELIMITER // CREATE PROCEDURE productpricing() BEGIN SELECT Avg(prod_price) AS priceaverage FROM products; END // DELIMITER ;
其中,DELIMITER //告訴命令行實用程序使用//做爲新的語句結束分隔符,能夠看到標誌存儲過程結束的END定義爲END //而不是END;。這樣,存儲過程體內的;仍然保持不動,而且正確地傳遞給數據庫引擎。最後,爲恢復爲原來的語句分隔符,可以使用DELIMITER ;。
除\符號外,任何字符均可以用做語句分隔符。
那麼,如何使用這個存儲過程:
CALL productpricing();
分析CALL productprincing();執行剛建立的存儲過程並顯示返回的結果。由於存儲過程其實是一種函數,因此存儲過程名後須要有()符號(即便不傳遞參數也須要)。
三、刪除存儲過程
存儲過程在建立後,被保存在服務器上供使用,直至被刪除。刪除命令(相似於刪除表的語句)從服務器中刪除存儲過程。
爲刪除剛建立的存儲過程,可以使用如下語句:
DROP PROCEDURE productpricing;
分析:這條語句刪除剛建立的存儲過程。請注意沒有使用後面的(),只給出存儲過程名。
注意:僅當存在時刪除 若是指定的過程不存在,則DROP PROCEDURE將產生一個錯誤。當過程存在想刪除它時(若是過程不存在也不產生錯誤)可以使用DROP PROCEDURE IF EXTSTS。
四、使用參數
productpricing只是一個簡單的存儲過程,它簡單地顯示SELECT語句的結果。通常,存儲過程並不顯示結果,而是把結果返回給你指定的變量
變量:內存中一個特定的位置,用來臨時存儲數據。
如下是productpricing的修改版本(若是不先刪除此存儲過程,則不能再次建立它):
CREATE PROCEDURE productpricing( OUT pl DECIMAL(8,2), OUT ph DECIMAL(8,2), OUT pa DECIMAL(8,2) ) BEGIN SELECT Min(prod_price) INTO pl FROM products; SELECT Max(prod_price) INTO ph FROM products; SELECT Avg(prod_price) INTO pa FROM products; END;
分析:此存儲過程接受3個參數:pl存儲產品最低價格,ph存儲產品最高價格,pa存儲產品平均價格。每一個參數必須具備指定的類型,這裏使用十進制。關鍵字OUT指出相應的參數用來從存儲過程傳出一個值(返回給調用者)。MySQL支持IN(傳遞給存儲過程)、OUT(從存儲過程傳出,如這裏所用)和INOUT(對存儲過程傳入和傳出)類型的參數。存儲過程的代碼位於BEGIN和END語句內,如所見,它們是一系列SELECT語句,用來檢索值,而後保存到相應的變量(經過制定INTO關鍵字)。
注意:參數的數據類型 存儲過程的參數容許的數據類型與表中使用的數據類型相同。注意,記錄集不是容許的類型,所以,不能經過一個參數返回多個行和列。這就是前面的例子爲何要使用3個參數(和3條SELECT語句)的緣由。
CALL productpricing( @pricelow, @pricehigh, @priceaverage);
分析:因爲此存儲過程要求3個參數,所以必須正好傳遞3個參數,很少也很多。因此,這條CALL語句給出3個參數。它們是存儲過程將保存結果的3個變量的名字。
變量名:全部MySQL變量都必須以@開始。
在調用時,這條語句並不顯示任何數據。它返回之後能夠顯示(或在其餘處理中使用)的變量。
爲了顯示檢索出的產品平均價格,可以下進行:
SELECT @priceaverage;
爲了得到3個值,可以使用如下語句:
SELECT @pricehigh,@pricelow,@priceaverage;
下面是另一個例子,此次使用IN和OUT參數。ordertotal接受訂單號並返回該訂單的合計:
CREATE PROCEDURE ordertotal( IN onumber INT, OUT ototal DECIMAL(8,2) ) BEGIN SELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumder INTO ototal; END;
分析:onumber定義爲IN,由於訂單號被傳入存儲過程。ototal定義爲OUT,由於要從存儲過程返回合計。SELECT語句使用這兩個參數,WHERE子句使用onumber選擇正確的行,INTO使用ototal存儲計算出來的合計。
爲調用這個心存儲過程,可以使用如下語句:
CALL ordertotal(20005,@total);
分析:必須給ordertotal傳遞兩個參數;第一個參數爲訂單號,第二個參數爲包含計算出來的合計的變量名。
爲了顯示此合計,可以下進行:
SELECT @total;
分析:@total已由ordertotal的CALL語句填寫,SELECT顯示它包含的值。
爲了獲得另外一個訂單的合計顯示,須要再次調用存儲過程,而後從新顯示變量:
CALL ordertotal(20009,@total); SELECT @total;
五、創建智能存儲過程
迄今爲止使用的全部存儲過程基本上都是封裝MySQL簡單的SELECT語句。雖然它們全都是有效的存儲過程例子,但它們所能完成的工做你直接用這些被封裝的語句就能完成(若是說它們還能帶來更多的東西,那就是使事情變得更復雜)。只有在存儲過程內包含業務規則和智能處理時,它們的威力才真正顯現出來。
考慮這個場景。你須要得到與之前同樣的訂單合計,但須要對合計增長營業稅,不過只針對某些顧客(或許是你所在州中那些顧客)。那麼,你須要作下面幾件事情:
(1)得到合計(與之前同樣);
(2)把營業稅有條件地添加到合計;
(3)返回合計(帶或不帶稅)。
存儲過程的完整工做以下:
-- Name:ordertotal -- Parameters:onumber = order number -- taxable = 0 if not taxable,1 if taxable -- ototal = order total variable CREATE PROCEDURE ordertotal( IN onumber INT, IN taxable BOOLEAN, OUT ototal DECIMAL(8,2) ) COMMENT 'Obtain order total,optionally adding tax' BEGIN -- Declare variable for total DECLARE total DECIMAL(8,2); -- Declare tax percentage DECLARE taxrate INT DEFAULT 6; -- Get the order total SELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumder INTO ototal; -- Is this taxable? IF taxable THEN --Yes,so add taxrate to the total SELECT total + (total / 100 * taxrate) INTO total; END IF; --And finally,save to out variable SELECT total INTO ototal; END;
分析:存儲過程有很大的變更。首先,增長了註釋(前面放置--)。在存儲過程複雜性增長時,這樣作特別重要。添加了另一個參數taxable,它是一個布爾值(若是要增長稅則爲真,不然爲假)。在存儲過程當中,用DECLARE語句定義了兩個局部變量。DECLARE要求制定變量名和數據類型,它也支持可選的默認值(這個例子中的taxrate的默認被設置爲6%)。SELECT語句已經改變,所以其結果存儲到total(局部變量)而不是ototal。IF語句檢查taxable是否爲真,若是爲真,則用另外一SELECT語句增長營業稅到局部變量total。最後,用另外一SELECT語句將total(它增長或許不增長營業稅)保存到ototal。
注意:COMMENT關鍵字 本例子中的存儲過程在CREATE PROCEDURE語句中包含了一個COMMENT值。它不是必需的,但若是給出,將在SHOW PROCEDURE STATUS的結果中顯示。
這顯然是一個更高級,功能更強的存儲過程。爲試驗它,請用如下兩條語句:
CALL ordertotal(20005,0,@total); SELECT @total;
CALL ordertotal(20005,1,@total); SELECT @total;
分析:BOOLEAN值指定爲1表示真,指定爲0表示假(實際上,非零值都考慮爲真,只有0被視爲假)。經過給中間的參數指定0或1,能夠有條件地將營業稅加到訂單合計上。
注意:IF語句 這個例子給出了MySQL的IF語句的基本用法。IF語句還支持ELSEIF和ELSE子句(前者仍是用THEN子句,後者不使用)。在之後博客中咱們將會看到IF的其餘用法(以及其餘流控制語句)。
六、檢查存儲過程
爲顯示用來建立一個存儲過程的CREATE語句,使用SHOW CREATE PROCEDURE語句:
SHOW CREATE PROCEDURE ordertotal;
爲了得到包括什麼時候、由誰建立等詳細信息的存儲過程列表,使用SHOW PROCEDURE STATUS
注意:限制過程狀態結果 SHOW PROCEDURE STATUS列出全部存儲過程。爲限制其輸出,可以使用LIKE指定一個過濾模式,例如:SHOW PROCEDURE STATUS LIKE 'ordertotal';
4、小結
本博客介紹了什麼是存儲過程以及爲何要使用存儲過程。咱們介紹了存儲過程的執行和建立的語法以及使用存儲過程的一些方法。下一個博客咱們將繼續這個話題。