關於預算系統存在小部分模組逾時的問題,我一直都認為是通過VPN訪問伺服器速度太慢所致。但是,我在.16測試伺服器和我自己本地的部署的伺服器進行測試的時候,逾時情況仍然存在。查閱網上相關資料修改Web.config之類,延長所謂的資料庫伺服器會話時間,沒有什麼效果。
下面我以“科目明細匯入”逾時為例,講解預算系統出現資料訪問逾時的主要原因。
之所以把問題給拿出來,是因為我想得出幾個結論。首先,基於目前預算系統的架構,在一個的事務範圍之內,對同一個表進行多次操作,如果存在某一個動作陳述式沒有包括在事務當中,則會造成等待逾時現象。(之所以這樣,是因為事務對某一個表已經進行的鎖定,事務之外的動作無法訪問該表)
其實,等待逾時,也算是死結的一種表現。回顧預算系統的多使用者並行作業所造成的死結現象,其實就是事務之間對錶的交叉訪問(這裡的事務是不嚴謹的),造成線程之間的相互等待,都擷取不了需要的資源,而造成的死結現象。並行作業造成的死結現象,這個問題的解決存在一定的複雜性,尚未有非常好的解決方案,只能從細節去抓。
這種事務機制,危害巨大。在引入資料庫緩衝依賴的時候,也同樣因為這個問題報錯
之所以報這種錯誤,是因為事務嵌套所致。在一個大的事務範圍之類,子方法使用了引用了事務,但是在整個大的事務範圍之內尚沒有執行完成,而在方法中有把事務給Commit和Rollback了,所以事務已經執行完。而我們在另外一個方法中提交,將會導致事務的無法使用。
/// <summary> /// 2013-01-18添加 /// 封裝DataBase的ExecuteDataSet函數,返回DataTable /// </summary> /// <param name="sqlCmd">字元型預存程序</param> /// <param name="pReadUncommitted">是否髒讀</param> /// <param name="Params">參數列表</param> /// <returns></returns> protected virtual DataTable ExecuteDataTable(string sqlCmd, bool pReadUncommitted, System.Data.Common.DbParameter[] Params,DbTransaction tran) { DataSet ds = null; DataTable dataTable = new DataTable(); Database db = CreateDatabase(); if (pReadUncommitted) { DbConnection conn = CreateDatabase().CreateConnection(); conn.Open(); try { DbCommand dbcommand = db.GetSqlStringCommand(sqlCmd); for (int i = 0; i < Params.Length; i++) { db.AddInParameter(dbcommand, Params[i].ParameterName, Params[i].DbType, Params[i].Value); } ds = db.ExecuteDataSet(dbcommand, tran); //tran.Commit(); //在事務範圍之內,不應該提交事務,所以注釋了 if (ds.Tables.Count > 0) dataTable = ds.Tables[0]; else dataTable = null; if (conn.State == ConnectionState.Open) conn.Close(); } catch (Exception ex) { tran.Rollback(); if (conn.State == ConnectionState.Open) conn.Close(); throw ex; } } else { DbCommand dbcommand = db.GetSqlStringCommand(sqlCmd); for (int i = 0; i < Params.Length; i++) { db.AddInParameter(dbcommand, Params[i].ParameterName, Params[i].DbType, Params[i].Value); } ds = db.ExecuteDataSet(dbcommand); if (ds.Tables.Count > 0) dataTable = ds.Tables[0]; else dataTable = null; } return dataTable; }