1. 程式人生 > >儲存過程的使用和基礎語法,以及.Net呼叫儲存過程的方法

儲存過程的使用和基礎語法,以及.Net呼叫儲存過程的方法

1、儲存過程的概念

儲存過程是一組為了完成特定功能的SQL語句集,儲存在資料庫中,經過第一次呼叫編譯後,再次呼叫不需要編譯。使用者通過指定儲存過程的名字並給出引數 (如果該儲存過程帶有引數) 來執行它 , 儲存過程是資料庫中的一個重要物件 ; 儲存過程中可以包含 邏輯控制語句 和 資料操縱語句 , 它可以接受引數 , 輸出引數 , 返回單個或多個結果集以及返回值

2、儲存過程的優缺點

優點:
1、執行速度:對於很簡單的sql,儲存過程沒有什麼優勢。對於複雜的業務邏輯,因為在儲存過程建立的時候,資料庫已經對其進行了一次解析和優化。儲存過程一旦執行,在記憶體中就會保留一份這個儲存過程,這樣下次再執行同樣的儲存過程時,可以從記憶體中直接呼叫,所以執行速度會比普通sql快。
2、可維護性

:的儲存過程有些時候比程式更容易維護,這是因為可以實時更新DB端的儲存過程。 有些bug,直接改儲存過程裡的業務邏輯,就搞定了。
3、 可擴充套件性:應用程式和資料庫操作分開,獨立進行,而不是相互在一起。方便以後的擴充套件和DBA維護優化
4、增強安全性 :
通過向用戶授予對儲存過程 (而不是基於表) 的訪問許可權 , 它們可以提供對特定資料的訪問 ;
提高程式碼安全 , 防止 SQL注入 (但未徹底解決 , 例如將資料操作語言 DML 附加到輸入引數)

缺點:
1、可移植性差 , 由於儲存過程將應用程式繫結到 Server , 因此使用儲存過程封裝業務邏輯將限制應用程式的可移植性 ; 如果應用程式的可移植性在您的環境中非常重要 , 則將業務邏輯封裝在不特定於 RDBMS

的中間層中可能是一個更佳的選擇 ;

3、建立儲存過程的基本語法

建立

if (!exists (select * from sys.objects where name = 'pro_name'))  //判斷資料庫中是否已經存在該儲存過程,若存在就刪除。
  drop proc pro_name                                               //PS:我覺著不太合適吧,存在就刪除,應該是不存在就建立吧  
go
create proc pro_name
    @param_name param_type [=default_value]
as
begin    
    sql語句
end

param_type表示引數型別,後面是引數的值,[ ]表示非必寫內容。
sys.objects儲存的是本資料庫中的資訊,不僅僅儲存表名,還有儲存過程名 、檢視名、觸發器等等。
SQL Server 實用工具將 GO 解釋為應將當前的 Transact-SQL 批處理語句傳送給 SQL Server 的訊號。當前批處理語句是自上一 GO 命令後輸入的所有語句,若是第一條 GO 命令,則是從特殊會話或指令碼的開始處到這條 GO 命令之間的所有語句。

呼叫

exec dbo.儲存過程名 引數值;

一般在執行儲存過程是,最好加上架構名稱,例如 dbo.USP_GetAllUser 這樣可以可以減少不必要的系統開銷,提高效能。 因為如果在儲存過程名稱前面沒有加上架構名稱,SQL SERVER 首先會從當前資料庫sys schema(系統架構)開始查詢,如果沒有找到,則會去其它schema查詢,最後在dbo架構(系統管理員架構)裡面查詢。

一個簡單的根據ID查詢使用者表的儲存過程

if (exists(select * from  sys.objects where name='GetUser'))
    drop proc GetUser
go 
create proc GetUser
    @id int output, //output意為該引數可以輸出
    @name varchar(20) out  //out為輸出引數
as 
begin 
    select @id=Id,@name=Name from UserInfo where [email protected]
end

go 
declare  //declare用於宣告引數
@name varchar(20),
@id int;
set @id=3; //賦值
exec dbo.GetUser @id,@name out;
select @id,@name;

分頁獲取資料的儲存過程

if (exists(select * from  sys.objects where name='GetUserByPage'))
    drop proc GetUserByPage
go 
create proc GetUserByPage
    @pageIndex int,
    @pageSize int
as 
declare 
@startIndex int,
@endIndex int;
set @startIndex =  (@pageIndex-1)*@pageSize+1;
set @endIndex = @startIndex + @pageSize -1 ;
begin 
    select Id,Name from 
    (
        select *,row_number()over (order by Id)as number from UserInfo  
    )t where t.number>[email protected] and t.number<[email protected]
end

go 
exec dbo.GetUserByPage 2,4;

事務的應用例項

if (exists(select * from  sys.objects where name='JayJayToTest'))
    drop proc JayJayToTest
go 
create proc JayJayToTest
    @GiveMoney int,
    @UserName nvarchar(20)
as 
beginset nocount on;
    begin tran;
    begin try
        update BankTest set Money = [email protected] where [email protected];
        update BankTest set Money = [email protected] where Name='test';
        commit;
    end try    
    begin catch        
        rollback tran;
        print ('發生異常,事務進行回滾');
    end catch    
end
go
exec JayJayToTest 10,'jayjay'

以上文章整理來源 https://www.cnblogs.com/sunniest/p/4386296.html

3.Net呼叫儲存過程

1.無引數無返回值的儲存過程
無返回值的儲存過程可以執行增加記錄、刪除記錄、修改記錄等資料庫操作。使用命令物件執行無返回值儲存過程和無返回值的Sql語句執行方式基本相同,都是使用ExecuteQuery()。

Create Proc ch_Person

as

    Update Person

        Set psnAddress=’乞力馬紮羅’

    Where psnName=’帕瓦羅蒂’

Go

要通過C#執行該儲存過程,需要建立一個SqlCommand類的命令物件,然後修改命令物件的型別屬性CommandType為儲存過程型別,並設定命令物件的CommandText為儲存過程的名字,然後通過ExecuteNonQuery()方法執行儲存過程即可:

SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");

try
{
    cn.Open();
    SqlCommandcmd=cn.CreateCommand();
    //設定命令型別為儲存過程
    cmd.CommandType=CommandType.StoreProcedure;
    //設定儲存過程的名字
    cmd.CommandText="ch_Person";
    //執行儲存過程
    cmd.ExecuteNonQuery();
}
catch(SqlExecption ex)
{
    //資料庫出錯資訊提示
}
finally
 {
    cn.Close();
}

2.帶引數

Create Proc ch_Person

    @p_psnName NvarChar(5),

    @p_psnAddress NvarChar(50)

As

   Update Person

       Set [email protected]_psnAddress

   Where [email protected]_psnName

Go

呼叫這個儲存過程又需要用到命令物件中的引數屬性Parameters,只需要在這個引數集合里加入儲存過程的引數定義並設定其值就可以了,程式碼如下:

SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");

try

{

  cn.Open();

  SqlCommandcmd=new SqlCommand("ch_Person",cn);

  cmd.CommandType=CommandType.StoredProcedure;

//加入引數物件,並設定其值

  cmd.Parameters.Add("@p_psnName",SqlDbType.NVarChar).Value="帕瓦羅蒂";

  cmd.Parameters.Add("@p_psnAddress",SqlDbType.NVarChar).Value="日本廣島";

//執行儲存過程

  cmd.ExecuteNonQuery();

}

catch(SqlException ex)

{

  //操作資料庫出錯資訊處理

}

finally

{

  cn.Close();

}

  1. 呼叫帶返回值的儲存過程
Create Proc gt_Address

   @p_psnName NvarChar(5)  //請輸入姓名

   @g_psnAddress NvarChar(5)OutPut  //返回此人的地址

As

   [email protected]_psnAddress=psnAddress From Person

   [email protected]_psnName

   [email protected]@Error<>0

       Return-1   //如果查詢語句出錯返回-1

   Else

       Return 0

Go

對於帶引數的儲存過程,不管是輸入引數還是輸出引數,實際上有一種簡單的方式建立引數,就是使用系統類SqlCommandBuilder的靜態方法DeriveParameters自動生成引數。使用DeriveParameters方法可以從SqlCommand中指定的儲存過程中檢索引數資訊並填充到該SqlCommand物件的Parameters集合裡。我們使用DeriveParameters方法重新實現上面的儲存過程呼叫如下:

SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");

try

{

   cn.Open();

   SqlCommandcmd=new SqlCommand("gt_Address",cn);

   cmd.CommandType=CommandType.StoredProcedure;

   //為命令物件生成引數

   SqlCommandBuilder.DeriveParameters(cmd);

   //設定輸入引數的值

   cmd.Parameters.Add("@p_psnName",SqlDbType.NvarChar).Value="帕瓦羅蒂";

   //執行儲存過程

   cmd.ExecuteNonQuery();

 

   int res=(int)cmd.Parameters["@Return"].Value;

   string address=(string)cmd.Parameters["@p_psnAddress"].Value;

   Console.WriteLine("返回值:{0},地址:{1}",res,address);  

}

catch(SqlException ex)

{

   //資料庫出錯資訊報告

}

finally

{

   cn.Close();

}