異步的SQL數據庫封裝詳解。本站提示廣大學習愛好者:(異步的SQL數據庫封裝詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是異步的SQL數據庫封裝詳解正文
引言
我一向在尋覓一種簡略有用的庫,它能在簡化數據庫相干的編程的同時供給一種異步的辦法來預防逝世鎖。
我找到的年夜部門庫要末太繁瑣,要末靈巧性缺乏,所以我決議本身寫個。
應用這個庫,你可以輕松地銜接就任何 SQL-Server 數據庫,履行任何存儲進程或 T-SQL 查詢,並異步地吸收查詢成果。這個庫采取 C# 開辟,沒有其他內部依附。
配景
你能夠須要一些事宜驅動編程的配景常識,但這不是必須的。
應用
這個庫由兩個類構成:
1、BLL (Business Logic Layer) 供給拜訪MS-SQL數據庫、履行敕令和查詢並將成果前往給挪用者的辦法和屬性。你不克不及直接挪用這個類的對象,它只供其他類繼續.
2、DAL (Data Access Layer) 你須要本身編寫履行SQL存儲進程和查詢的函數,而且關於分歧的表你能夠須要分歧的DAL類。
起首,你須要像如許創立 DAL 類:
namespace SQLWrapper { public class DAL : BLL { public DAL(string server, string db, string user, string pass) { base.Start(server, db, user, pass); } ~DAL() { base.Stop(eStopType.ForceStopAll); } /////////////////////////////////////////////////////////// // TODO: Here you can add your code here... } }
因為BLL類保護著處置異步查詢的線程,你須要供給需要的數據來拼接銜接字符串。萬萬別忘了挪用`Stop`函數,不然析構函數會強迫挪用它。
NOTE:假如須要銜接其他非MS-SQL數據庫,你可以經由過程修正BLL類中的`CreateConnectionString`函數來生成適合的銜接字符串。
為了挪用存儲進程,你應當在DAL中編寫這類函數:
public int MyStoreProcedure(int param1, string param2) { // 依據存儲進程的前往類型創立用戶數據 StoredProcedureCallbackResult userData = new StoredProcedureCallbackResult(eRequestType.Scalar); // 在此界說傳入存儲進程的參數,假如沒有參數可以省略 <span >userData.Parameters = new System.Data.SqlClient.SqlParameter[] { </span> new System.Data.SqlClient.SqlParameter("@param1", param1), new System.Data.SqlClient.SqlParameter("@param2", param2), }; // Execute procedure... if (!ExecuteStoredProcedure("usp_MyStoreProcedure", userData)) throw new Exception("Execution failed"); // 期待履行完成... // 期待時長為 <userdata.tswaitforresult> // 履行未完成前往 <timeout> if (WaitSqlCompletes(userData) != eWaitForSQLResult.Success) throw new Exception("Execution failed"); // Get the result... return userData.ScalarValue; }
正如你所看到的,存儲進程的前往值類型可所以`Scalar`,`Reader`和`NonQuery`。關於 `Scalar`,`userData`的`ScalarValue`參數成心義(即前往成果);關於`NonQuery`,`userData`的 `AffectedRows`參數就是受影響的行數;關於`Reader`類型,`ReturnValue`就是函數的前往值,別的你可以經由過程 `userData`的`resultDataReader`參數拜訪recordset。
再看看這個示例:
public bool MySQLQuery(int param1, string param2) { // Create user data according to return type of store procedure in SQL(這個正文沒有更新,解釋《正文是魔鬼》有點事理) ReaderQueryCallbackResult userData = new ReaderQueryCallbackResult(); string sqlCommand = string.Format("SELECT TOP(1) * FROM tbl1 WHERE code = {0} AND name LIKE '%{1}%'", param1, param2); // Execute procedure... if (!ExecuteSQLStatement(sqlCommand, userData)) return false; // Wait until it finishes... // Note, it will wait (userData.tsWaitForResult) // for the command to be completed otherwise returns <timeout> if (WaitSqlCompletes(userData) != eWaitForSQLResult.Success) return false; // Get the result... if(userData.resultDataReader.HasRows && userData.resultDataReader.Read()) { // Do whatever you want.... int field1 = GetIntValueOfDBField(userData.resultDataReader["Field1"], -1); string field2 = GetStringValueOfDBField(userData.resultDataReader["Field2"], null); Nullable<datetime> field3 = GetDateValueOfDBField(userData.resultDataReader["Field3"], null); float field4 = GetFloatValueOfDBField(userData.resultDataReader["Field4"], 0); long field5 = GetLongValueOfDBField(userData.resultDataReader["Field5"], -1); } userData.resultDataReader.Dispose(); return true; }
在這個例子中,我們挪用 `ExecuteSQLStatement` 直接履行了一個SQL查詢,但思惟跟 `ExecuteStoredProcedure` 是一樣的。
我們應用 `resultDataReader` 的 `.Read()` 辦法來迭代處置前往的成果集。別的供給了一些helper辦法來防止疊代中因為NULL字段、GetIntValueOfDBField 等惹起的異常。
假如你要履行 SQL 敕令而不是存儲進程,須要傳入 ExecuteSQLStatement 的 userData 有三類:
1、ReaderQueryCallbackResult userData:實用於有前往recordset的語句,可以經由過程userData.resultDataReader取得對前往的recordset的拜訪。
2、NonQueryCallbackResult userData:實用於像UPDATE這類沒有前往內容的語句,可使用userData.AffectedRows檢討履行的成果。
3、ScalarQueryCallbackResult userData:用於查詢語句只前往一個標量值的情形,例如`SELECT code FROM tbl WHEN ID=10`,經由過程userData.ScalarValue 獲得前往的成果。
關於存儲進程,只要一種須要傳入 ExecuteStoredProcedure 的數據類型。但在聲明變量時你須要指明存儲進程的前往值類型:
StoredProcedureCallbackResult userData(eRequestType):除聲明分歧外,其他操作與下面雷同。
異步地應用代碼
借使你不願望挪用線程被查詢壅塞,你須要周期性地挪用 `WaitSqlCompletes` 來檢討查詢能否完成,履行能否掉敗。
/// <summary> /// 你須要周期性地挪用WaitSqlCompletes(userData, 10) /// 來檢查成果能否可用! /// </summary> public StoredProcedureCallbackResult MyStoreProcedureASYNC(int param1, string param2) { // Create user data according to return type of store procedure in SQL StoredProcedureCallbackResult userData = new StoredProcedureCallbackResult(eRequestType.Reader); // If your store procedure accepts some parameters, define them here, // or you can omit it incase there is no parameter definition userData.Parameters = new System.Data.SqlClient.SqlParameter[] { new System.Data.SqlClient.SqlParameter("@param1", param1), new System.Data.SqlClient.SqlParameter("@param2", param2), }; // Execute procedure... if (!ExecuteStoredProcedure("usp_MyStoreProcedure", userData)) throw new Exception("Execution failed"); return userData; }
在挪用線程中你須要如許做:
... DAL.StoredProcedureCallbackResult userData = myDal.MyStoreProcedureASYNC(10,"hello"); ... // each time we wait 10 milliseconds to see the result... switch(myDal.WaitSqlCompletes(userData, 10)) { case eWaitForSQLResult.Waiting: goto WAIT_MORE; case eWaitForSQLResult.Success: goto GET_THE_RESULT; default: goto EXECUTION_FAILED; } ...
數據庫狀況
在 BLL 中只要一個異步地供給數據庫狀況的事宜。假如數據庫銜接被斷開了(平日是因為收集成績),OnDatabaseStatusChanged 事宜就會被掛起。
別的,假如銜接恢復了,這個事宜會被再次掛起來告訴你新的數據庫狀況。
風趣的處所
在我開辟代碼的時刻,我明確了銜接字符串中的銜接時限(connection timeout)和SQL敕令對象的履行時限(execution timeout)異樣主要。
起首,你必需認識到最年夜允許時限是在銜接字符串中界說的,並可以給出一些履行指令比銜接字符串中的超不時間更長的時光。
其次,每個敕令都有著它們本身的履行時限,在這裡的代碼中默許為30秒。你可以很輕易地修正它,使它實用於一切類型的敕令,就像如許:
userData.tsWaitForResult = TimeSpan.FromSeconds(15);
以上就是異步的SQL數據庫封裝全體進程,願望對年夜家的進修有所贊助。