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

10年積累的成都做網(wǎng)站、網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有原陽(yáng)免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
以下,以幾個(gè)問(wèn)題去闡述本文要說(shuō)的核心!
1. 要及時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接?
——這個(gè)答案,是肯定的,即:要及時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接。無(wú)論在你的項(xiàng)目里數(shù)據(jù)庫(kù)訪問(wèn)(操作)是否有用連接池,都需要及時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接(ps: 連接池的關(guān)閉數(shù)據(jù)庫(kù)連接,并不是真正意義上的關(guān)閉,而是(通過(guò)close()方法)將當(dāng)前使用的連接放回到連接池中)。但卻不要及時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接,why?——答案在第二個(gè)問(wèn)題中,將會(huì)做出解答。
2.數(shù)據(jù)庫(kù)連接打開與關(guān)閉,(為了確保'連接用時(shí)打開用完立即關(guān)閉'的原則),要在每次數(shù)據(jù)庫(kù)操作時(shí)都去打開和關(guān)閉連接嗎?
——在給出解答之前,先看如下代碼("配餐系統(tǒng)" 中 分頁(yè)查詢的方法)
- 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)養(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)養(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;
- }
大家看后,會(huì)發(fā)現(xiàn)此方法中,有以下幾點(diǎn)值得注意:
a.有些代碼后有 "http://[*]“——此用于標(biāo)識(shí)所在行代碼是執(zhí)行數(shù)據(jù)庫(kù)操作,方便大家能清楚的知道 try/catch 代碼塊中有幾處數(shù)據(jù)庫(kù)(連接)操作
b.DBHelper.OpenCon();和DBHelper.CloseCon(); ——大家大概可以知道:此try/catch 代碼塊中只有一次數(shù)據(jù)庫(kù)打開和關(guān)閉,——事實(shí)上也確實(shí)只有一次。再看下其中涉及(調(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] (此方法需要 手動(dòng)(即調(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方法(此方法最終是對(duì)ExecuteScalar_Object_Other方法)的調(diào)用,這樣如果是reader中有20條記錄, 并且在ExecuteScalar_Object_Other方法內(nèi)部(查詢)操作開始前打開連接,結(jié)束時(shí)關(guān)閉連接,此while循環(huán)代碼塊執(zhí)行完——將可能有20*2=40次的數(shù)據(jù)庫(kù)連接打開與關(guān)閉操作,假設(shè):每次數(shù)據(jù)庫(kù)連接打開與關(guān)閉操作需要0.1s的時(shí)間,那么此while循環(huán)代碼塊將需要至少0.1*40=4s的時(shí)間執(zhí)行,再加上其它的查詢或更多更頻繁的數(shù)據(jù)庫(kù)操作, 效率就可想而知。【這個(gè)得回到在此文一開始所說(shuō)的,“有些東西你以為弄清楚明白了,其實(shí)未必”。在之前未做winform開發(fā)(確切的說(shuō)是 沒(méi)有使用access數(shù)據(jù)庫(kù)時(shí)),數(shù)據(jù)庫(kù)操作方法,都是如下方法([舊DBHelper類中的]:即在方法內(nèi)部,連接即開即關(guān)。也是網(wǎng)上很多通用DBHelper數(shù)據(jù)庫(kù)操作類中的寫法),因?yàn)樵陧?xiàng)目中用的都是mysql,sqlserver這種大型的數(shù)據(jù)庫(kù), 即使不用連接池,數(shù)據(jù)量不大的情況下,查詢等速度都比access數(shù)據(jù)庫(kù)要快的多,那時(shí)還感覺自己略作優(yōu)化過(guò)的DBHelper類已經(jīng)夠用了,效果也還不錯(cuò)。但是在做winform"配餐系統(tǒng)"開發(fā)時(shí),用的是access數(shù)據(jù)庫(kù),還用之前的DBHelper類,也是做GetFoodInfosList方法中相同的查詢操作(當(dāng)時(shí)還沒(méi)考慮分頁(yè)),問(wèn)題就暴露出來(lái)了——只查詢10條左右的記錄,界面卻等待了3s左右,結(jié)果才(卡)出來(lái)。 出現(xiàn)了問(wèn)題,只能查看代碼思考解決問(wèn)題:數(shù)據(jù)庫(kù)操作代碼還是之前項(xiàng)目中的DBHelper類中,為什么會(huì)查詢速度如此之慢呢?后慢慢想明白和知道:access數(shù)據(jù)庫(kù)跟mysql,sqlserver等大型的數(shù)據(jù)庫(kù)相比,性能差了很多,數(shù)據(jù)庫(kù)性能差,而也不考慮換用其它的數(shù)據(jù)庫(kù),只能在代碼上做優(yōu)化,于是修改了DBHelper類,類似于重構(gòu)了部分方法——以適應(yīng)不同情況下的需要?!?/p>
[舊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();
- }
- }
好了,到這兒,可以對(duì)以上兩個(gè)問(wèn)題一起做個(gè)答復(fù),闡明此文的關(guān)鍵點(diǎn):數(shù)據(jù)庫(kù)連接的打開和關(guān)閉,要在當(dāng)前可見范圍內(nèi)或代碼塊中 數(shù)據(jù)庫(kù)操作開始前 打開連接,在無(wú)需(或者說(shuō)***一個(gè))數(shù)據(jù)庫(kù)操作后 關(guān)閉連接,舉例:在一個(gè)方法或代碼塊中,如上GetFoodInfosList方法;在一個(gè)事件中,如:一個(gè)按鈕的點(diǎn)擊事件中:可能會(huì)執(zhí)行n次數(shù)據(jù)庫(kù) 增刪改差等操作....
結(jié)束語(yǔ):應(yīng)該是***次寫這么長(zhǎng)的技術(shù)文章,寫的比較艱難,呵呵...,感覺把自己知道的東西想寫的讓別人能很容易看懂且不丟失自己想說(shuō)的,不是一件容易的事。后附的是***的DBHelper類(里面還有一些地方可以或需要優(yōu)化),希望路過(guò)的朋友能多提意見或交流你的看法!
***的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):手動(dòng)(即調(diào)用OpenCon(); CloseCon();方法)打開和關(guān)閉連接
- * 方法注釋中有[Notice Con] 或 [Notice Connection] 或方法名中含有“_Other”,則調(diào)用的是以下的方法
- * */
- #region 數(shù)據(jù)庫(kù)操作方法
- ///
- /// 執(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ù)庫(kù)連接都需要顯示關(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語(yǔ)句,實(shí)現(xiàn)數(shù)據(jù)庫(kù)事務(wù)。
- ///
- /// name = "SQLStringList" >多條SQL語(yǔ)句
- 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ù)庫(kù)連接方法
- ///
- ///
數(shù)據(jù)庫(kù)連接 returns> - private static void Getconn()
- {
- if (conObject == null)
- conObject = new OleDbConnection(Connstr);
- }
- ///
- /// 獲得并打開數(shù)據(jù)庫(kù)連接方法
- ///
- ///
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ù)庫(kù)連接方法
- ///
- public static void CloseCon()
- {
- if (conObject != null && conObject.State != ConnectionState.Closed)
- conObject.Close();
- }
- #endregion
- #region 數(shù)據(jù)庫(kù)操作方法
- public static int GetMaxID(string FieldName, string TableName)
- {
- string strsql = "select max(" + FieldName + ") from " + TableName;
- try
- {
- return GetScalar(strsql);
- }
- &n
文章標(biāo)題:淺談配餐系統(tǒng)中數(shù)據(jù)庫(kù)連接打開與關(guān)閉
URL網(wǎng)址:http://www.dlmjj.cn/article/dpodhcg.html


咨詢
建站咨詢
