存儲過程—— C#中調用存儲過程的簡單示例

shanzm-2020年5月3日 23:23:44

0. 簡介

【定義】:存儲過程(Stored Procedure) 是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,它存儲在數據庫中,一次編譯後永久有效,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。git

【優缺點】:存儲過程優缺點都很是的明顯!幾乎每一篇討論存儲過程的文字,都是會說其餘優勢是balabala,缺點是balabala,然而最後做者的結論都是:「我不推薦使用存儲過程」
具體的存儲過程的優缺點這裏就不詳述了!github

公司舊項目使用存儲過程實現業務邏輯,沒辦法只能研究了一下 🙃!sql

閒言碎語不要講,書歸正傳,下面就開始存儲過程!數據庫



1. 語法細節

  1. 變量與變量之間使用逗號隔開,語句結尾無標點符號編程

  2. 聲明變量:declare @variate_name variate_type,例如聲明並賦值:declare @name nvarchar(50) ='shanzm'
    變量賦值:set @variate_name =value
    打印變量:print @variate_name編輯器

  3. begin……end 之間的SQL語句稱之爲一個代碼塊測試

  4. 可使用if……else實現邏輯判斷spa

  5. 建立存儲過程:create procedure pro_namecode

  6. 執行存儲過程:execute pro_nameip

  7. 輸出參數:存儲過程返回的是SQL語句查閱結果,在定義參數後,添加output,設置爲一個輸出參數(和C#中輸出參數相似),至關於多了一個返回值!

  8. 建立存儲過程的基本形式:

create procedure pro_name_tableName
@param1 param1_type,
@param2 param2_type,
as
begin 
SET NOCOUNT ON;--關閉返回受影響行數
    --sql語句
end
go


2. 示例1:模擬轉帳

①示例背景:使用存儲過程,模擬在一張存款表中實現用戶與用戶之間的轉帳

②準備工做1:在數據庫中建立表szmBank

CREATE TABLE [dbo].[szmBank](
	[Id] [bigint] IDENTITY(1,1) NOT NULL,
	[Balance] [decimal](18, 0) NOT NULL

添加一些測試數據:

Id                   Balance
---------------      ----------------
1                    1000
2                    2000
3                    3000

③準備工做2:封裝C#代碼中的SQL輔助類SqlHelper

注意封裝的時候要有一個CommandType參數,決定是執行SQL語句仍是存儲過程,
CommandType是一個枚舉類型,其中Text值爲執行SQL語句,StoreProcedure爲執行存儲過程
具體封裝細節這裏就不詳述了。

找到了2年前我封裝的一個SqlHelper.cs,常規使用沒有任何問題,僅供參考:

#region
// ===============================================================================
// Project Name        :    
// Project Description : 
// ===============================================================================
// Class Name          :    SqlHelper
// Class Version       :    v1.0.0.0
// Class Description   :    SQL語句輔助類
// CLR                 :    4.0.30319.18408  
// Author              :    shanzm
// Create Time         :    2018-8-14 18:22:59
// Update Time         :    2018-8-14 18:22:59
// ===============================================================================
// Copyright © SHANZM-PC  2018 . All rights reserved.
// ===============================================================================
#endregion

using System.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace _16StoreProcedure
{
    public class SqlHelper
    {
        private static readonly string connStr =
            ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;

        /// <summary>
        /// 返回查詢結果的的表
        /// </summary>
        /// <param name="sql">SQL語句或存儲過程</param>
        /// <param name="type">執行類型</param>
        /// <param name="param">參數</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sql, CommandType type, params  SqlParameter[] param)
        {
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                using (SqlDataAdapter adapter = new SqlDataAdapter(sql, conn))
                {
                    if (param != null)
                    {
                        adapter.SelectCommand.Parameters.AddRange(param);
                    }

                    adapter.SelectCommand.CommandType = type;
                    DataTable da = new DataTable();
                    adapter.Fill(da);
                    return da;
                }
            }
        }



        /// <summary>
        /// 返回影響行數
        /// </summary>
        /// <param name="sql">SQL語句或存儲過程</param>
        /// <param name="type">執行類型</param>
        /// <param name="param">參數</param>
        /// <returns></returns>
        public static int ExecuteNonquery(string sql, CommandType type, params SqlParameter[] param)
        {
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    if (param != null)
                    {
                        cmd.Parameters.AddRange(param);
                    }
                    cmd.CommandType = type;
                    conn.Open();
                    return cmd.ExecuteNonQuery();

                }
            }

        }

        /// <summary>
        /// 返回查詢結果的第一行第一個單元格的數據
        /// </summary>
        /// <param name="sql">SQL語句或存儲過程</param>
        /// <param name="type">執行類型</param>
        /// <param name="param">參數</param>
        /// <returns></returns>
        public static object ExecuteScalar(string sql, CommandType type, params SqlParameter[] param)
        {
            using (SqlConnection conn=new SqlConnection (connStr ))
            {
                using (SqlCommand cmd=new SqlCommand (sql,conn))
                {
                    if (param !=null )
                    {
                        cmd.Parameters.AddRange(param);
                    }
                    cmd.CommandType = type ;
                    conn.Open();
                    return cmd.ExecuteScalar();
                }
            }
        }

    }
}

④編寫存儲過程
在數據庫中:指定數據庫-->可編程性-->存儲過程-->右鍵:新建-->存儲過程:

SQL Server中編寫的SQL語句沒有默認的格式化,全部代碼排版按照我本身習慣進行Tab縮進
建議放到編輯器中查看下面的存儲過程,會好看一些!
SQL大小寫不敏感,我習慣小寫,方便閱讀!

-- =============================================
-- Author:		shanzm
-- Create date: 2020年5月2日 19:56:51
-- Description:	模擬帳戶之間轉帳
-- =============================================
create procedure pro_transfer_szmbank
@from bigint,
@to bigint,
@balance decimal(18,0),
@returnNum int output--(1表示轉帳成功,2表示失敗,3表示餘額不足)
as
begin
	--判斷轉出帳戶是否有足夠的金額
	declare @money decimal(18,0)
	select @money=Balance from dbo.szmBank where Id=@from; 
	if @money-@balance>=0.1	
		    --開始轉帳
			begin 
				begin transaction
					declare @sum int =0
					--轉出帳戶扣錢
					update szmBank set balance=balance-@balance where id=@from
					set @sum=@sum+@@error
					--轉入帳戶加錢
					update szmBank set balance=balance+@balance where id=@to
					set @sum=@sum+@@error
					--判斷是否成功
					if @sum<>0
						begin
							set @returnNum=2--轉帳失敗
							rollback
						end
					else
						begin
							set @returnNum=1--轉帳成功
							commit
						end
			end
	else
		begin
			set @returnNum=3--餘額不足
		end
end
go

在數據庫中執行測試(F5):

--執行測試:
declare @ret int
execute pro_transfer_szmbank 
@from='1',
@to='2',
@balance='10',
@returnNum=@ret output--注意輸出參數在執行語句中也是要代表"output"
print @ret  --結果是打印:1,即存儲過程實現成功

【注意】:

  • @@ERROR:當前一個語句遇到錯誤,則返回錯誤碼(好比除零錯誤的錯誤碼是:8134),不然返回0。

    須要注意的是@@ERROR只對其前一條sql語句有效,在每一條語句執行後會被馬上重置,所以應該在要驗證的語句執行後檢查數值或者是將它保存到局部變量中以備未來使用。

  • 咱們須要查看某個存儲過程,則可使用數據中自帶的存儲過程查看:
    sp_helptext pro_transfer_szmBank

  • 修改現有的存儲過程,右鍵存儲過程-->修改:顯示的存儲過程只是把建立存儲過程當中的create變爲了alert

  • 能夠在SQL Server的SQL窗口選中某些SQL語句,點擊執行,即執行選中的SQL語句

⑤控制檯中測試

新建一個控制檯項目,在配置文件中添加鏈接字符串

由於封裝的SqlHelper中須要從配置文件中讀取數據庫鏈接字符串,因此添加引用:System.Configuration

static void Main(string[] args)
{
    //轉出帳戶的Id
    int from = 1;
    //轉入帳戶的Id
    int to = 2;
    //轉帳金額
    decimal balance = 10;

    SqlParameter[] param =
    {
        new SqlParameter ("@from",from),
        new SqlParameter("@to",to),
        new SqlParameter ("@balance",balance),
        //-------------------------------注意:這裏設置爲輸出參數
        new SqlParameter ("@returnNum",System.Data.SqlDbType.Int{Direction=System.Data.ParameterDirection.Output }
    };

    //------------------------設置CommonType爲StorProcedure類型
    SqlHelper.ExecuteNonquery("pro_transfer_szmbank",System.Data.CommandType.StoredProcedure, param);

    //------------------------獲取輸出參數
    //根據輸出參數判斷轉帳結果
    int outPutparam = Convert.ToInt16(param[3].Value);

    switch (outPutparam)
    {
        case 1: Console.WriteLine($"success:從Id:{from}轉帳{balance}元到Id:{to}");break;
        case 2: Console.WriteLine("error"); break;
        case 3: Console.WriteLine("餘額不足"); break;
    }

    Console.ReadKey();
}

測試結果:

success:從Id:1轉帳10元到Id:2


3. 示例2:測試返回DataTable

①存儲過程

create  procedure [dbo].[pro_ReturnDataTable]
as
begin
	select Id as 用戶ID ,Balance as 餘額 from szmBank;
end
go

②數據庫中測試

execute pro_ReturnDataTable

測試結果:即顯示szmBank中的全部數據

③控制檯中測試

static void Main(string[] args)
{
    DataTable dt = SqlHelper.GetDataTable("pro_ReturnDataTable", CommandType.StoredProcedure);
    foreach (DataRow row in dt.Rows)
    {
        Console.WriteLine(row["用戶ID"].ToString() + ":" + row["餘額"].ToString());
    }
    Console.ReadKey();
    //TransferAccounts();
    ReturnDataTable();
}

測試結果:即打印szmBank中的全部數據



4. 源代碼下載

  • C#中使用存儲過程-源代碼下載

  • 所須要的數據庫表在示例中已說明,能夠直接使用建表語句建立!

  • 存儲過程的SQL語句在示例中完整的展現了,能夠直接複製!

相關文章
相關標籤/搜索