新聞中心
做程序開發(fā)到現(xiàn)在已有三年多的時間了,先不說技術(shù)已達(dá)到了什么樣的一個水平,就對自己熟悉或比較精通的技術(shù)等——感覺需要再繼續(xù)深究或清楚其如何用好(提升性能)的東西還不少[簡單的說:就是有些自認(rèn)為懂的技術(shù),其實未必真懂,了解的可能只是部分或不是合適的用法]。這篇文章要說就是——對程序性能起著很大決定性作用的數(shù)據(jù)庫操作(一般情況下:優(yōu)化數(shù)據(jù)庫(包括數(shù)據(jù)庫操作),比優(yōu)化代碼對性能提升的效果更顯著的多),——數(shù)據(jù)庫連接打開與關(guān)閉 的時間和范圍。

10年積累的成都做網(wǎng)站、網(wǎng)站建設(shè)經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計后付款的網(wǎng)站建設(shè)流程,更有原陽免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
以下,以幾個問題去闡述本文要說的核心!
1. 要及時關(guān)閉數(shù)據(jù)庫連接?
——這個答案,是肯定的,即:要及時關(guān)閉數(shù)據(jù)庫連接。無論在你的項目里數(shù)據(jù)庫訪問(操作)是否有用連接池,都需要及時關(guān)閉數(shù)據(jù)庫連接(ps: 連接池的關(guān)閉數(shù)據(jù)庫連接,并不是真正意義上的關(guān)閉,而是(通過close()方法)將當(dāng)前使用的連接放回到連接池中)。但卻不要及時關(guān)閉數(shù)據(jù)庫連接,why?——答案在第二個問題中,將會做出解答。
2.數(shù)據(jù)庫連接打開與關(guān)閉,(為了確保'連接用時打開用完立即關(guān)閉'的原則),要在每次數(shù)據(jù)庫操作時都去打開和關(guān)閉連接嗎?
——在給出解答之前,先看如下代碼("配餐系統(tǒng)" 中 分頁查詢的方法)
- public static IList GetFoodInfosList(string key, int type, int fid, int sid, string yysZdName, int pageSize, int currentPage, ref int xxCount, ref int pageCount)
- {
- List list = new List ();
- xxCount = 0;
- pageCount = 0;
- //是否需要按營養(yǎng)素排序
- bool isNeedOrder = false;
- Dictionary
dictCx = null; - Dictionary dictFlName = new Dictionary ();
- string ids = String.Empty;
- string flId = String.Empty;
- string flName = String.Empty;
- string fieldList = " id,name,fid,Sid,type,IsSys ";
- #region 組合where條件
- //省略
- #endregion
- OleDbDataReader reader = null;
- try
- {
- DBHelper.OpenCon();
- //得到信息總條數(shù)
- xxCount = GetFoodInfosXxCount(where);//[*]
- pageCount = FenyeHelper.GetPageCount(xxCount, pageSize);
- ZhiyiModel.JustNeed.FoodInfo foodinfo = null;
- reader = FenyeHelper.PageView_Reader_Other2("food", fieldList, "id", where, "", false, pageSize, currentPage, pageCount, xxCount);//[*]
- while (reader.Read())
- {
- foodinfo = new ZhiyiModel.JustNeed.FoodInfo();
- foodinfo.Id = (int)reader["id"];
- foodinfo.IsSys = (int)reader["IsSys"];
- foodinfo.FoodName = reader["name"].ToString();
- flId = reader["fid"].ToString();
- foodinfo.FirstFl = GetFlName(dictFlName, flId, flName);//[*]
- flId = reader["Sid"].ToString();
- foodinfo.SecondFl = GetFlName(dictFlName, flId, flName);//[*]
- foodinfo.FoodType = reader["type"].ToString() == "0" ? "原料" : "菜肴";
- foodinfo.Heat = YysPropertyService.GetYysInfoByFoodId("heat", foodinfo.Id,"0");//[*]
- if (isNeedOrder)
- {
- dictCx.Add(foodinfo.Id, foodinfo);
- ids += string.IsNullOrEmpty(ids) ? foodinfo.Id.ToString() : "," + foodinfo.Id;
- }
- else
- list.Add(foodinfo);
- }
- #region 按營養(yǎng)素排序
- if (isNeedOrder && !string.IsNullOrEmpty(ids))
- {
- DBHelper.CloseReader(reader);
- //[*]
- reader = DBHelper.GetReader_Other2("select foodid from xxxxxxxxxxxxx", CommandType.Text);
- int foodId = 0;
- list.Clear();
- while (reader.Read())
- {
- foodId = (int)reader["foodid"];
- foodinfo = new ZhiyiModel.JustNeed.FoodInfo();
- if (!dictCx.TryGetValue(foodId, out foodinfo))
- continue;
- list.Add(foodinfo);
- }
- }
- #endregion
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- DBHelper.CloseReader(reader);
- DBHelper.CloseCon();
- dictCx = null;
- }
- return list;
- }
大家看后,會發(fā)現(xiàn)此方法中,有以下幾點值得注意:
a.有些代碼后有 "http://[*]“——此用于標(biāo)識所在行代碼是執(zhí)行數(shù)據(jù)庫操作,方便大家能清楚的知道 try/catch 代碼塊中有幾處數(shù)據(jù)庫(連接)操作
b.DBHelper.OpenCon();和DBHelper.CloseCon(); ——大家大概可以知道:此try/catch 代碼塊中只有一次數(shù)據(jù)庫打開和關(guān)閉,——事實上也確實只有一次。再看下其中涉及(調(diào)用)到的部分方法:
- private static string GetFlName(Dictionary dictFlName, string flId, string flName)
- {
- flName = string.Empty;
- if (!string.IsNullOrEmpty(flId) && flId != "0")
- {
- if (!dictFlName.TryGetValue(flId, out flName))
- {
- flName = ShiwuClassService.GetShiwuClassNameById(flId);
- dictFlName.Add(flId, flName);
- }
- }
- return flName;
- }
- ///
- /// [Notice Conn]
- ///
- /// name = "id" >
- ///
returns> - public static string GetShiwuClassNameById(string id)
- {
- object obj = DBHelper.ExecuteScalar_Object_Other(string.Format("select name from xxxx where id={0}",id), CommandType.Text);
- return obj == null ? "" : obj.ToString();
- }
- ///
- /// 返回***行***列的值[Object] (此方法需要 手動(即調(diào)用OpenCon(); CloseCon();方法)打開和關(guān)閉連接)
- ///
- ///
returns> - public static object ExecuteScalar_Object_Other(string sql, CommandType comType, params OleDbParameter[] sqlParams)
- {
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = comType;
- cmd.CommandTimeout = 180;
- DBHelper.SetParams(cmd, sqlParams);
- try
- {
- return cmd.ExecuteScalar();
- }
- catch (OleDbException ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- }
- }
在 while循環(huán)代碼塊中 有兩次GetFlName方法(此方法最終是對ExecuteScalar_Object_Other方法)的調(diào)用,這樣如果是reader中有20條記錄, 并且在ExecuteScalar_Object_Other方法內(nèi)部(查詢)操作開始前打開連接,結(jié)束時關(guān)閉連接,此while循環(huán)代碼塊執(zhí)行完——將可能有20*2=40次的數(shù)據(jù)庫連接打開與關(guān)閉操作,假設(shè):每次數(shù)據(jù)庫連接打開與關(guān)閉操作需要0.1s的時間,那么此while循環(huán)代碼塊將需要至少0.1*40=4s的時間執(zhí)行,再加上其它的查詢或更多更頻繁的數(shù)據(jù)庫操作, 效率就可想而知。【這個得回到在此文一開始所說的,“有些東西你以為弄清楚明白了,其實未必”。在之前未做winform開發(fā)(確切的說是 沒有使用access數(shù)據(jù)庫時),數(shù)據(jù)庫操作方法,都是如下方法([舊DBHelper類中的]:即在方法內(nèi)部,連接即開即關(guān)。也是網(wǎng)上很多通用DBHelper數(shù)據(jù)庫操作類中的寫法),因為在項目中用的都是mysql,sqlserver這種大型的數(shù)據(jù)庫, 即使不用連接池,數(shù)據(jù)量不大的情況下,查詢等速度都比access數(shù)據(jù)庫要快的多,那時還感覺自己略作優(yōu)化過的DBHelper類已經(jīng)夠用了,效果也還不錯。但是在做winform"配餐系統(tǒng)"開發(fā)時,用的是access數(shù)據(jù)庫,還用之前的DBHelper類,也是做GetFoodInfosList方法中相同的查詢操作(當(dāng)時還沒考慮分頁),問題就暴露出來了——只查詢10條左右的記錄,界面卻等待了3s左右,結(jié)果才(卡)出來。 出現(xiàn)了問題,只能查看代碼思考解決問題:數(shù)據(jù)庫操作代碼還是之前項目中的DBHelper類中,為什么會查詢速度如此之慢呢?后慢慢想明白和知道:access數(shù)據(jù)庫跟mysql,sqlserver等大型的數(shù)據(jù)庫相比,性能差了很多,數(shù)據(jù)庫性能差,而也不考慮換用其它的數(shù)據(jù)庫,只能在代碼上做優(yōu)化,于是修改了DBHelper類,類似于重構(gòu)了部分方法——以適應(yīng)不同情況下的需要。】
[舊DBHelper類中的]:
- ///
- /// 返回***行***列的值[Object]
- ///
- ///
returns> - public static object ExecuteScalar1(string sql, CommandType comType, params OleDbParameter[] sqlParams)
- {
- OpenCon();
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = comType;
- cmd.CommandTimeout = 180;
- DBHelper.SetParams(cmd, sqlParams);
- try
- {
- return cmd.ExecuteScalar();
- }
- catch (OleDbException ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- CloseCon();
- }
- }
好了,到這兒,可以對以上兩個問題一起做個答復(fù),闡明此文的關(guān)鍵點:數(shù)據(jù)庫連接的打開和關(guān)閉,要在當(dāng)前可見范圍內(nèi)或代碼塊中 數(shù)據(jù)庫操作開始前 打開連接,在無需(或者說***一個)數(shù)據(jù)庫操作后 關(guān)閉連接,舉例:在一個方法或代碼塊中,如上GetFoodInfosList方法;在一個事件中,如:一個按鈕的點擊事件中:可能會執(zhí)行n次數(shù)據(jù)庫 增刪改差等操作....
結(jié)束語:應(yīng)該是***次寫這么長的技術(shù)文章,寫的比較艱難,呵呵...,感覺把自己知道的東西想寫的讓別人能很容易看懂且不丟失自己想說的,不是一件容易的事。后附的是***的DBHelper類(里面還有一些地方可以或需要優(yōu)化),希望路過的朋友能多提意見或交流你的看法!
***的DBHelper類:
- using System;
- using System.Collections.Generic;
- using System.Text;using System.Data.OleDb;using System.Data;
- namespace ZhiyiHelper
- {
- public partial class DBHelper
- {
- /**
- * 以下的方法需要在調(diào)用的可見區(qū)域內(nèi):手動(即調(diào)用OpenCon(); CloseCon();方法)打開和關(guān)閉連接
- * 方法注釋中有[Notice Con] 或 [Notice Connection] 或方法名中含有“_Other”,則調(diào)用的是以下的方法
- * */
- #region 數(shù)據(jù)庫操作方法
- ///
- /// 執(zhí)行增,刪,改命令的方法
- ///
- /// name = "sql" >
- ///
returns> - public static int Execute_Other(string sql, CommandType commandType, params OleDbParameter[] sqlParams)
- {
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = commandType;
- cmd.CommandTimeout = 180;
- SetParams(cmd, sqlParams);
- try
- {
- return cmd.ExecuteNonQuery();
- }
- catch (OleDbException ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- }
- }
- ///
- /// 返回***行***列的值[Int]
- ///
- /// name = "sql" >
- ///
returns> - public static int ExecuteScalar_Int_Other(string sql, CommandType comType, params OleDbParameter[] sqlParams)
- {
- object reObj = ExecuteScalar_Object_Other(sql, comType, sqlParams);
- return reObj == null ? 0 : Convert.ToInt32(reObj);
- }
- ///
- /// 返回***行***列的值[Object]
- ///
- ///
returns> - public static object ExecuteScalar_Object_Other(string sql, CommandType comType, params OleDbParameter[] sqlParams)
- {
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = comType;
- cmd.CommandTimeout = 180;
- DBHelper.SetParams(cmd, sqlParams);
- try
- {
- return cmd.ExecuteScalar();
- }
- catch (OleDbException ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- }
- }
- ///
- /// 返回OleDbDataReader的方法
- ///
- /// name = "sql" >
- /// name = "commandType" >
- /// name = "sqlParams" >
- ///
returns> - public static OleDbDataReader GetReader_Other(string sql, CommandType commandType, params OleDbParameter[] sqlParams)
- {
- OleDbDataReader reader = null;
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = commandType;
- SetParams(cmd, sqlParams);
- try
- {
- reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- }
- return reader;
- }
- ///
- /// 返回OleDbDataReader的方法 [reader和數(shù)據(jù)庫連接都需要顯示關(guān)閉]
- ///
- /// name = "sql" >
- /// name = "commandType" >
- /// name = "sqlParams" >
- ///
returns> - public static OleDbDataReader GetReader_Other2(string sql, CommandType commandType, params OleDbParameter[] sqlParams)
- {
- OleDbDataReader reader = null;
- OleDbCommand cmd = new OleDbCommand(sql, conObject);
- cmd.CommandType = commandType;
- SetParams(cmd, sqlParams);
- try
- {
- reader = cmd.ExecuteReader();
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- //釋放資源
- DisponseCmd(cmd);
- }
- return reader;
- }
- ///
- /// 執(zhí)行多條SQL語句,實現(xiàn)數(shù)據(jù)庫事務(wù)。
- ///
- /// name = "SQLStringList" >多條SQL語句
- public static void ExecuteSqlTran_Other(List SQLStringList)
- {
- if (SQLStringList == null || SQLStringList.Count == 0)
- return;
- OleDbCommand cmd = new OleDbCommand();
- cmd.Connection = conObject;
- cmd.CommandType = CommandType.Text;
- OleDbTransaction tx = conObject.BeginTransaction();
- cmd.Transaction = tx;
- try
- {
- string sql = String.Empty;
- for (int n = 0; n < SQLStringList.Count; n++)
- {
- sql = SQLStringList[n];
- if (sql.Trim().Length > 1)
- {
- cmd.CommandText = sql;
- cmd.ExecuteNonQuery();
- }
- }
- tx.Commit();
- }
- catch (System.Data.OleDb.OleDbException e)
- {
- tx.Rollback();
- throw e;
- }
- finally
- {
- //釋放資源
- if (tx != null)
- {
- tx.Dispose();
- tx = null;
- }
- DisponseCmd(cmd);
- }
- }
- ///
- /// 關(guān)閉和釋放數(shù)據(jù)讀取器
- ///
- /// name = "reader" >
- public static void CloseReader(OleDbDataReader reader)
- {
- if (reader != null && reader.IsClosed)
- {
- reader.Dispose();
- reader.Close();
- reader = null;
- }
- }
- #endregion
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Data.OleDb;using System.Data;
- using System.Configuration;
- namespace ZhiyiHelper{
- public partial class DBHelper
- {
- private static string connstr = String.Empty;
- private static OleDbConnection conObject = null;
- public DBHelper()
- {
- }
- #region 基礎(chǔ)方法
- ///
- /// 獲取連接字符串的屬性
- ///
- private static string Connstr
- {
- get
- {
- if (connstr == String.Empty)
- {
- connstr = ConfigHelper.GetConnectionStringsString("accessConSql");
- connstr = GetConnString();
- }
- return connstr;
- }
- }
- ///
- /// 得到數(shù)據(jù)庫連接方法
- ///
- ///
數(shù)據(jù)庫連接 returns> - private static void Getconn()
- {
- if (conObject == null)
- conObject = new OleDbConnection(Connstr);
- }
- ///
- /// 獲得并打開數(shù)據(jù)庫連接方法
- ///
- ///
returns> - public static void OpenCon()
- {
- Getconn();
- if (conObject.State == ConnectionState.Open)
- return;
- if (conObject.State != ConnectionState.Closed)
- conObject.Close();
- conObject.Open();
- }
- ///
- /// 關(guān)閉數(shù)據(jù)庫連接方法
- ///
- public static void CloseCon()
- {
- if (conObject != null && conObject.State != ConnectionState.Closed)
- conObject.Close();
- }
- #endregion
- #region 數(shù)據(jù)庫操作方法
- public static int GetMaxID(string FieldName, string TableName)
- {
- string strsql = "select max(" + FieldName + ") from " + TableName;
- try
- {
- return GetScalar(strsql);
- }
- &n
網(wǎng)站名稱:淺談配餐系統(tǒng)中數(shù)據(jù)庫連接打開與關(guān)閉
文章起源:http://m.5511xx.com/article/dpodhcg.html


咨詢
建站咨詢
