C#程序調用Sql Server存儲過程異常處理:調用存儲過程后不返回、不拋異常的解決方案

目錄

一、代碼解析:

二、解決方案

1、增加日志記錄

2、異步操作

注意事項

3、增加超時機制

4、使用線程池

5、使用信號量或事件

6、監控數據庫連接狀態


在C#程序操作Sql Server數據庫的實際應用中,若異常就會拋出異常,我們還能找到異常的原因,進一步去解決;但偶發的不返回、也不拋出異常的情況真是令人頭疼,下面我將從C#程序代碼層面去分析解決思路,先上代碼

        /// <summary>/// 執行存儲過程,返回影響的行數/// </summary>/// <param name="procedureName">存儲過程名</param>/// <param name="parameters">自定義參數數組,根據調用數據庫的種類,給參數中相應的數組賦值</param>/// <returns></returns>public int ExecuteProcedure(string procedureName, object[] aParas){SqlCommand cmd = new SqlCommand();try{PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);int rows = cmd.ExecuteNonQuery();cmd.Parameters.Clear();return rows;}catch (Exception err){throw err;}} 

一、代碼解析:

我們解析下這個函數,這個也是一個比較簡單常用的方法:

這個函數的作用是執行一個存儲過程,并返回該存儲過程執行后影響的行數。下面是對函數各個部分的詳細解釋:

函數定義

/// <summary>
/// 執行存儲過程,返回影響的行數
/// </summary>
/// <param name="procedureName">存儲過程名</param>
/// <param name="parameters">自定義參數數組,根據調用數據庫的種類,給參數中相應的數組賦值</param>
/// <returns></returns>
public int ExecuteProcedure(string procedureName, object[] aParas)
  • summary: 該函數用于執行存儲過程并返回影響的行數。
  • param:?procedureName?是存儲過程的名稱。
  • param:?parameters?是一個自定義參數數組,根據調用數據庫的種類,給參數中相應的數組賦值。
  • returns: 返回存儲過程執行后影響的行數。

函數實現

public int ExecuteProcedure(string procedureName, object[] aParas)
{//創建SqlCommand對象SqlCommand cmd = new SqlCommand();try{//調用PrepareCommand方法來設置SqlCommand對象的參數,包括連接對象con、命令對象cmd、命令類型(這里是存儲過程)、存儲過程名稱和參數數組。PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);//使用ExecuteNonQuery方法執行存儲過程,并返回影響的行數。int rows = cmd.ExecuteNonQuery();//清除SqlCommand對象的參數,以便下次使用。cmd.Parameters.Clear();return rows;}catch (Exception err){//捕獲并拋出任何可能發生的異常。throw err;}
}

????????這個函數的主要作用是執行一個存儲過程,并返回該存儲過程執行后影響的行數。它通過設置SqlCommand對象的參數,執行存儲過程,并處理可能發生的異常。

二、解決方案

? ? ? ? 問題:在實際應用中遇到這種情況,即在調用 ExecuteProcedure 方法后,沒有到達 return rows; 語句,也沒有進入 catch (Exception err) 塊,這意味著代碼在某個地方被阻塞或掛起,但沒有拋出異常。這可能是由于以下幾種情況之一:

  1. 死鎖或資源爭用

    • 數據庫連接可能被其他操作占用,導致當前操作無法繼續執行。
    • 數據庫中的某個存儲過程可能存在死鎖,導致執行被阻塞。
  2. 無限循環或長時間運行的操作

    • 存儲過程中可能存在無限循環或長時間運行的操作,導致執行時間過長。
  3. 網絡問題

    • 數據庫服務器或網絡連接可能出現問題,導致請求無法完成。
  4. 線程問題

    • 當前線程可能被其他線程或操作阻塞,導致無法繼續執行。
  5. 內存或資源耗盡

    • 系統內存或資源可能耗盡,導致無法繼續執行。

解決方法

  1. 增加日志記錄

    • 在關鍵步驟增加更多的日志記錄,以便更好地了解代碼執行到哪個步驟。
  2. 檢查數據庫狀態

    • 檢查數據庫服務器的狀態,查看是否有死鎖或其他問題。
    • 使用數據庫管理工具監控數據庫性能和資源使用情況。
  3. 優化存儲過程

    • 檢查存儲過程的邏輯,確保沒有無限循環或長時間運行的操作。
    • 優化存儲過程的性能,減少資源消耗。
  4. 檢查網絡連接

    • 確保數據庫服務器和應用程序之間的網絡連接穩定。
  5. 監控系統資源

    • 監控系統內存、CPU 和其他資源的使用情況,確保沒有資源耗盡的情況。
  6. 使用異步操作

    • 考慮將數據庫操作改為異步操作,以避免阻塞主線程。

????????因為問題是偶發的,半年一年出現一次,也找不出什么原因,但是客戶會較真,拿這個說事;以上方法,從代碼層面只有1、6適用 ,當然我們也可以通過控制超時 時間來處理,實用解決方案如下:

1、增加日志記錄

?關鍵步驟增加日志記錄,以便更好地了解代碼執行情況:

public int ExecuteProcedure(string procedureName, object[] aParas)
{SqlCommand cmd = new SqlCommand();try{// 增加日志記錄Log("Preparing command for procedure: " + procedureName);PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);// 增加日志記錄Log("Executing command for procedure: " + procedureName);int rows = cmd.ExecuteNonQuery();// 增加日志記錄Log("Command executed successfully, rows affected: " + rows);cmd.Parameters.Clear();return rows;}catch (Exception err){// 增加日志記錄Log("Exception occurred: " + err.Message);throw err;}
}private void Log(string message)
{// 實現日志記錄邏輯,例如寫入文件或數據庫Console.WriteLine(message);
}

????????通過增加日志記錄,可以更好地了解代碼執行到哪個步驟,從而更容易定位問題,這種特殊情況也只能定位到走哪一行就沒往下走了。

2、異步操

將數據庫操作改為異步操作可以提高應用程序的響應性和性能,特別是在處理大量數據或長時間運行的操作時。

使用?ExecuteNonQueryAsync?方法

SqlCommand 類提供了 ExecuteNonQueryAsync 方法,用于異步執行 SQL 命令。以下是修改后的 ExecuteProcedure 方法:

using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;public async Task<int> ExecuteProcedureAsync(string procedureName, object[] aParas)
{SqlCommand cmd = new SqlCommand();try{// 增加日志記錄Log("Preparing command for procedure: " + procedureName);PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);// 異步執行命令Log("Executing command for procedure: " + procedureName);int rows = await cmd.ExecuteNonQueryAsync();// 增加日志記錄Log("Command executed successfully, rows affected: " + rows);cmd.Parameters.Clear();return rows;}catch (Exception err){// 增加日志記錄Log("Exception occurred: " + err.Message);throw err;}
}private void Log(string message)
{// 實現日志記錄邏輯,例如寫入文件或數據庫Console.WriteLine(message);
}

調用異步方法

在調用異步方法時,需要使用 await 關鍵字,并且調用方法也必須是異步的。例如:

public async Task SomeMethodAsync()
{string procedureName = "YourStoredProcedureName";object[] parameters = new object[] { /* 參數值 */ };try{int rowsAffected = await ExecuteProcedureAsync(procedureName, parameters);Console.WriteLine("Rows affected: " + rowsAffected);}catch (Exception ex){Console.WriteLine("Exception: " + ex.Message);}
}

注意事項

  1. 異步方法的返回類型:異步方法的返回類型通常是?Task?或?Task<T>,其中?T?是方法的返回類型。
  2. 異步上下文:確保在異步上下文中調用異步方法,例如在?async?方法中使用?await
  3. 異常處理:異步方法中的異常處理與同步方法類似,但需要使用?await?關鍵字捕獲異常。

????????通過將數據庫操作改為異步操作,可以提高應用程序的性能和響應性,特別是在處理大量數據或長時間運行的操作時。

??????但是并不是所有程序都適合異步操作,那么將如何處理呢?

如果程序邏輯不能使用異步方式,但仍然遇到在調用 ExecuteProcedure 方法后沒有到達 return rows; 語句的問題,可以考慮以下幾種方法來解決這個問題:

3、增加超時機制

為數據庫操作增加超時機制,確保操作不會無限期地阻塞。可以使用 SqlCommandCommandTimeout 屬性來設置超時時間。

public int ExecuteProcedure(string procedureName, object[] aParas)
{SqlCommand cmd = new SqlCommand();try{// 設置命令超時時間為30秒cmd.CommandTimeout = 30;PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);int rows = cmd.ExecuteNonQuery();cmd.Parameters.Clear();return rows;}catch (Exception err){throw err;}
}

????????這個超時機制在特殊情況下沒有用,親測沒用,就算不設置CommandTimeout屬性的值,也有默認的吧,特殊情況等多久都沒返回沒異常。

4、使用線程池

將數據庫操作放在單獨的線程中執行,并在主線程中等待結果。可以使用 ThreadPoolTask 來實現這一點。

using System.Threading;public int ExecuteProcedure(string procedureName, object[] aParas)
{int rows = 0;bool isCompleted = false;Exception exception = null;ThreadPool.QueueUserWorkItem(_ =>{SqlCommand cmd = new SqlCommand();try{PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);rows = cmd.ExecuteNonQuery();cmd.Parameters.Clear();}catch (Exception err){exception = err;}finally{isCompleted = true;}});// 等待操作完成或超時DateTime startTime = DateTime.Now;while (!isCompleted && (DateTime.Now - startTime).TotalSeconds < 30){Thread.Sleep(100);}if (exception != null){throw exception;}if (!isCompleted){throw new TimeoutException("Database operation timed out.");}return rows;
}

5、使用信號量或事件

使用信號量或事件來同步主線程和數據庫操作線程。

using System.Threading;public int ExecuteProcedure(string procedureName, object[] aParas)
{int rows = 0;Exception exception = null;ManualResetEvent completionEvent = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(_ =>{SqlCommand cmd = new SqlCommand();try{PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);rows = cmd.ExecuteNonQuery();cmd.Parameters.Clear();}catch (Exception err){exception = err;}finally{completionEvent.Set();}});// 等待操作完成或超時if (!completionEvent.WaitOne(TimeSpan.FromSeconds(30))){throw new TimeoutException("Database operation timed out.");}if (exception != null){throw exception;}return rows;
}

6、監控數據庫連接狀態

在執行數據庫操作之前,檢查數據庫連接的狀態,確保連接是可用的。

public int ExecuteProcedure(string procedureName, object[] aParas)
{SqlCommand cmd = new SqlCommand();try{// 檢查數據庫連接狀態if (con.State != ConnectionState.Open){con.Open();}PrepareCommand(con, cmd, null, CommandType.StoredProcedure, procedureName, aParas);int rows = cmd.ExecuteNonQuery();cmd.Parameters.Clear();return rows;}catch (Exception err){throw err;}
}

????????

通過以上方法,可以在不改變程序邏輯的情況下,增加超時機制、使用線程池、信號量或事件來解決數據庫操作阻塞的問題。這些方法可以幫助確保數據庫操作在合理的時間內完成,并在出現異常時及時處理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41812.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41812.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41812.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode 完美數

1.題目要求: 對于一個 正整數&#xff0c;如果它和除了它自身以外的所有 正因子 之和相等&#xff0c;我們稱它為 「完美數」。給定一個 整數 n&#xff0c; 如果是完美數&#xff0c;返回 true&#xff1b;否則返回 false。示例 1&#xff1a;輸入&#xff1a;num 28 輸出&a…

2024年6月份找工作和面試總結

轉眼間6月份已經過完了&#xff0c;2024年已經過了一半&#xff0c;希望大家都找到了合適的工作。 本人前段時間寫了5月份找工作的情況&#xff0c;請查看2024年5月份面試總結-CSDN博客 但是后續寫的總結被和諧了&#xff0c;不知道這篇文章能不能發出來。 1、6月份面試機會依…

網絡爬蟲基礎

網絡爬蟲基礎 網絡爬蟲&#xff0c;也被稱為網絡蜘蛛或爬蟲&#xff0c;是一種用于自動瀏覽互聯網并從網頁中提取信息的軟件程序。它們能夠訪問網站&#xff0c;解析頁面內容&#xff0c;并收集所需數據。Python語言因其簡潔的語法和強大的庫支持&#xff0c;成為實現網絡爬蟲…

verilog讀寫文件注意事項

想要的16進制數是文本格式提供的文件&#xff0c;想將16進制數提取到變量內&#xff0c; 可以使用 f s c a n f ( f d 1 , " 也可以使用 fscanf(fd1,"%h",rd_byte);實現 也可以使用 fscanf(fd1,"也可以使用readmemh(“./FILE/1.txt”,mem);//fe放在mem[0…

運用Redis作為設備注冊中心,解決20w+設備高并發讀寫,高性能讀寫異步把數據同步到mysql持久化。

使用 Redis 作為設備注冊中心&#xff0c;并通過高并發讀寫將數據異步同步到 MySQL 數據庫&#xff0c;可以采用以下策略&#xff1a; 1. **設備注冊與發現**&#xff1a; - 使用 Redis 的字符串或哈希表存儲設備信息&#xff0c;其中鍵可以是設備的唯一標識符。 2. **高并…

基于Android Studio零食工坊

目錄 項目介紹 圖片展示 運行環境 獲取方式 項目介紹 用戶 可以瀏覽商品 &#xff0c; 查詢商品 &#xff0c; 加入購物車 &#xff0c; 結算商品 &#xff0c; 查看瀏覽記錄 &#xff0c; 修改密碼 &#xff0c; 修改個人信息 &#xff0c; 查詢訂單 管理員 能夠實現商品的…

別再寫一堆 if 判斷了?分享 1 段優質 JS 代碼片段!

本內容首發于工粽號&#xff1a;程序員大澈&#xff0c;每日分享一段優質代碼片段&#xff0c;歡迎關注和投稿&#xff01; 大家好&#xff0c;我是大澈&#xff01; 本文約 700 字&#xff0c;整篇閱讀約需 1 分鐘。 今天分享一段優質 JS 代碼片段&#xff0c;用條件數組來簡…

huggingface筆記:gpt2

0 使用的tips GPT-2是一個具有絕對位置嵌入的模型&#xff0c;因此通常建議在輸入的右側而不是左側填充GPT-2是通過因果語言建模&#xff08;CLM&#xff09;目標進行訓練的&#xff0c;因此在預測序列中的下一個標記方面非常強大 利用這一特性&#xff0c;GPT-2可以生成語法連…

C#面 :ASP.Net Core中有哪些異常處理的方案?

在 ASP.NET Core中&#xff0c;有多種異常處理方案可供選擇。以下是其中幾種常見的異常處理方案&#xff1a; 中間件異常處理&#xff1a; ASP.NET Core提供了一個中間件來處理全局異常。通過在Startup類的Configure方法中添加UseExceptionHandler中間件&#xff0c;可以捕獲…

Autosar MCAL-S32k324 Crypto配置-RandomNumber生成及使用

文章目錄 前言CryptoPrimitivesCryptoPrimitiveAlgorithmFamilyCryptoPrimitiveAlgorithmModeCryptoPrimitiveAlgorithmSecondaryFamilyCryptoPrimitiveServiceCryptoDriverObject代碼使用Random Generate執行流程配置job函數使用示例總結前言 之前介紹過AES-CMAC算法的配置,…

Windows 與 Windows Server 2022環境下如何開啟遠程桌面

文章目錄 前言Windows 環境下如何開啟遠程桌面控制功能Windows Server 環境下如何開啟遠程桌面 前言 我這邊是客戶需要搭建一套備份系統&#xff0c;整體的系統流程是這樣的&#xff1a;客戶的筆記本或者其他PC工具可以自由訪問到我司搭建的服務器平臺并進行文件傳輸&#xff…

【C++】開源:地圖投影和坐標轉換proj庫配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 這篇文章主要介紹地圖投影和坐標轉換proj庫配置使用。 無專精則不能成&#xff0c;無涉獵則不能通。——梁啟超 歡迎來到我的博客&#xff0c;一起學習&#xff0c;共同進步。 喜歡的朋友可以關注一下&a…

vue中的watch和$watch的用法實際場景和區別

watch&#xff08;組件選項&#xff09; watch 是Vue組件的一個選項&#xff0c;它允許你定義一些監聽器&#xff0c;這些監聽器會在組件的響應式數據變化時調用。它主要用于組件內部的數據監聽。 實際場景&#xff1a; 當組件內部的數據變化時&#xff0c;需要執行一些操作&…

5款極其強大的大模型文生圖工具!

文生圖技術是一種基于深度學習的技術&#xff0c;可以根據自然語言描述生成相應的高品質圖像。 下面介紹幾個目前市場上比較優秀的工具或網站&#xff0c;并制作一張男性的白袍巫師圖來比較。 針對大模型和AIGC技術趨勢、AIGC 算法項目落地經驗分享、新手如何入門算法崗、該如…

el-scrollbar組件使用踩坑記錄

一、el-scrollbar和瀏覽器原生滾動條一起出現 問題描述 el-scrollbar組件主要用于替換瀏覽器原生導航條。如下圖所示&#xff0c;使用el-scrollbar組件后&#xff0c;發現未能成功替換掉瀏覽器原生導航條&#xff0c;二者同時出現。 引發原因 el-scrollbar的height屬性如果…

前端根據目錄生成模塊化路由routes

根據約定大于配置的邏輯&#xff0c;如果目錄結構約定俗成&#xff0c;前端是可以根據目錄結構動態生成路由所需要的 route 結構的&#xff0c;這個過程是要在編譯時 進行&#xff0c;生成需要的代碼&#xff0c;保證運行時的代碼正確即可 主流的打包工具都有對應的方法讀取文…

【不容錯過】可靈AI重磅更新:畫質升級,運鏡控制,首尾幀自定義,還有30萬創作激勵獎金!

還記得最近在各大平臺肆虐的老照片變成視頻嗎&#xff0c;就是用快手的可靈AI做的&#xff0c;今天可靈又迎來了一次重大更新。 「電腦端上線了」 之前一直用其他工具生的圖片還需要保存到手機上&#xff0c;再用可靈來生成視頻&#xff0c;很多人都能感受到手機操作不太方便&…

Vue3項目給ElementPlus設置中文的兩個方案

介紹 在Vue3項目將ElementPlus切換為中文 1、在App.vue的文件中修改 <template><el-config-provider :locale"zhCn"><router-view></router-view></el-config-provider> </template><script lang"ts" setup>im…

elasticsearch源碼分析-04集群狀態發布

集群狀態發布 cluster模塊封裝了在集群層面執行的任務&#xff0c;如集群健康、集群級元信息管理、分片分配給節點、節點管理等。集群任務執行之后可能會產生新的集群狀態&#xff0c;如果產生新的集群狀態主節點會將集群狀態廣播給其他節點。 集群狀態封裝在clusterState中&…

Linux下網絡編程-簡易poll服務器和客戶端

Linux下網絡編程-簡易poll服務器和客戶端 簡易poll服務器: //編譯命令&#xff1a;g -g xxx.cpp -o xxx #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h…