原文網址:http: //www.51la.org/webjx/htmldata/2005-12-24/1135405777.html
摘要預存程序的呼叫在b/s系統中用的很多。傳統的呼叫方法不僅速度慢,而且程式碼會隨著預存程序的增加而不斷膨脹,難以維護。新的方法在一定程度上解決了這些問題。
關鍵字asp.net;預存程序在使用.net的過程中,資料庫存取是一個很重要的部分,特別是在b/s系統的建置過程中,資料庫操作幾乎成為了一個必不可少的操作。呼叫預存程序實作資料庫操作使許多程式設計師使用的方法,而且大多數的程式設計師都是能使用預存程序就使用預存程序,很少直接使用sql語句,所以預存程序是很有用且很重要的。
預存程序簡介
簡單的說,預存程序是由一些sql語句和控制語句組成的被封裝起來的過程,它駐留在資料庫中,可以被客戶應用程式調用,也可以從另一個過程或觸發器調用。它的參數可以被傳遞和回傳。與應用程式中的函數過程類似,預存程序可以透過名字來調用,而且它們同樣有輸入參數和輸出參數。
根據傳回值類型的不同,我們可以將預存程序分為三類:傳回記錄集的預存程序, 傳回數值的預存程序(也可以稱為標量預存程序),以及行為預存程序。顧名思義,傳回記錄集的預存程序的執行結果是一個記錄集,典型的例子是從資料庫中擷取符合某一個或幾個條件的記錄;傳回數值的預存程序執行完以後會傳回一個值,例如在資料庫中執行一個有回傳值的函數或指令;最後,行為預存程序只是用來實現資料庫的某個功能,而沒有回傳值,例如在資料庫中的更新和刪除操作。
使用預存程序的好處
相對於直接使用sql語句,在應用程式中直接呼叫預存程序有以下好處:
(1)減少網路通訊量。呼叫一個行數不多的預存程序與直接呼叫sql語句的網路通訊量可能不會有很大的差別,可是如果預存程序包含上百行sql語句,那麼其效能絕對比一條一條的呼叫sql語句要高得多。
(2)執行速度更快。有兩個原因:首先,在預存程序建立的時候,資料庫已經對其進行了一次解析和最佳化。其次,預存程序一旦執行,在記憶體中就會保留一份這個預存過程,這樣下次再執行同樣的預存程序時,就可以從記憶體直接呼叫。
(3)更強的適應性:由於預存程序對資料庫的存取是透過預存程序來進行的,因此資料庫開發人員可以在不改動預存程序介面的情況下對資料庫進行任何改動,而這些改變不會對應用程式造成影響。
(4) 布式工作:應用程式和資料庫的編碼工作可以分別獨立進行,而不會相互壓制。
由以上的分析可以看到,在應用程式中使用預存程序是很有必要的。
兩種不同的預存程序呼叫方法
為了突顯新方法的優點,首先介紹在.net中呼叫預存程序的「官方」方法。另外,本文的所有範例程式均工作於sqlserver資料庫上,其它情況類似,以後不再一一說明。本文所有例子均採用c#語言。
要在應用程式中存取資料庫,一般性的步驟是:先聲明一個資料庫連接sqlconnection,然後聲明一個資料庫指令sqlcommand,用來執行sql語句和預存程序。有了這兩個物件後,就可以根據自己的需求採用不同的執行方式來達到目的。需要補充的是,不要忘記在頁面上添加如下的引用語句:using system.data.sqlclient。
就執行預存程序來說,如果執行的是第一類預存程序,那麼就要用一個dataadapter將結果填入一個dataset中,然後就可以使用資料網格控制項將結果呈現在頁面上了;如果執行的是第二和第三種儲存過程,則不需要此過程,只需要根據特定的返回判定操作是否成功完成即可。
(1)執行一個沒有參數的預存程序的程式碼如下:
sqlconnection conn=new sqlconnection(“connectionstring”);
sqldataadapter da = new sqldataadapter();
da.selectcommand = new sqlcommand();
da.selectcommand.connection = conn;
da.selectcommand.commandtext = "nameofprocedure";
da.selectcommand.commandtype = commandtype.storedprocedure;
然後只要選擇適當的方式執行此處流程,用於不同的目的即可。
(2)執行一個有參數的預存程序的程式碼如下(我們可以將呼叫預存程序的函數宣告為exeprocedure(string inputdate)):
sqlconnection conn=new sqlconnection(“connectionstring”);
sqldataadapter da = new sqldataadapter();
da.selectcommand = new sqlcommand();
da.selectcommand.connection = conn;
da.selectcommand.commandtext = "nameofprocedure";
da.selectcommand.commandtype = commandtype.storedprocedure;
(以上程式碼相同,以下為要新增的程式碼)
param = new sqlparameter("@parametername", sqldbtype.datetime);
param.direction = parameterdirection.input;
param.value = convert.todatetime(inputdate);
da.selectcommand.parameters.add(param);
這樣就增加了一個輸入參數。若需要新增輸出參數:
param = new sqlparameter("@parametername", sqldbtype.datetime);
param.direction = parameterdirection.output;
param.value = convert.todatetime(inputdate);
da.selectcommand.parameters.add(param);
若要獲得參儲過程的回傳值:
param = new sqlparameter("@parametername", sqldbtype.datetime);
param.direction = parameterdirection.returnvalue;
param.value = convert.todatetime(inputdate);
da.selectcommand.parameters.add(param);
從上面的程式碼我們可以看出,當預存程序比較多或預存程序的參數比較多時,這種方法會大大影響開發的速度;另一方面,如果項目比較大,那麼這些用於資料庫邏輯的函數在以後的維護中也是一個很大的負擔。那麼,有沒有一種改進的方法可以解決這個問題呢?想到在執行沒有參數的存儲過程時只需要傳入一個存儲過程的名字就可以調用相應的存儲過程,而且在sqlserver數據庫中我們可以直接在查詢分析器中敲入“存儲過程名(參數列表)”樣的字串就可以執行儲存過程,那麼,是否可以把這種想法應用到應用程式中呢?
於是在編譯器中鍵入對應程式碼。這些代碼是在呼叫不帶參數的預存程序的程式碼的基礎上改的。具體代碼如下:
sqlconnection conn=new sqlconnection(“connectionstring”);
sqldataadapter da = new sqldataadapter();
da.selectcommand = new sqlcommand();
da.selectcommand.connection = conn;
da.selectcommand.commandtext = "nameofprocedure('para1','para2',para3)";
da.selectcommand.commandtype = commandtype.storedprocedure;
為了使程式碼更具代表性,要呼叫的預存程序的第一個和第二個參數都為字串類型,第三個參數為整數。執行以後發現,完全可以達到預期的效果!
兩種呼叫方法的比較透過比較我們可以看到,第二種方法有一個很明顯的優點,那就是可以提高開發速度,節省開發時間,而且程式碼容易維護,在一定程度上也減少了系統大小。但是,由於對預存程序參數的處理比較籠統,如果要取得輸出參數或得到預存程序的回傳值,這種方法就不能滿足需求了。雖然如此,但是,這種方法畢竟可以讓開發人員少一些很大一部分的程式碼。如果不需要取得輸出參數和回傳值,那麼幾乎可以做到「一勞永逸」。因此在實際的程式開發中,這種方法還是具有一定的實用價值的。