做程序开发到现在已有三年多的时间了,先不说技术已达到了什么样的一个水平,就对自己熟悉或比较精通的技术等——感觉需要再继续深究或清楚其如何用好(提升性能)的东西还不少[简单的说:就是有些自认为懂的技术,其实未必真懂,了解的可能只是部分或不是合适的用法]。这篇文章要说就是——对程序性能起着很大决定性作用的数据库操作(一般情况下:优化数据库(包括数据库操作),比优化代码对性能提升的效果更显著的多),——数据库连接打开与关闭 的时间和范围。

10年积累的成都做网站、网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有原阳免费网站建设让你可以放心的选择与我们合作。
以下,以几个问题去阐述本文要说的核心!
1. 要及时关闭数据库连接?
——这个答案,是肯定的,即:要及时关闭数据库连接。无论在你的项目里数据库访问(操作)是否有用连接池,都需要及时关闭数据库连接(ps: 连接池的关闭数据库连接,并不是真正意义上的关闭,而是(通过close()方法)将当前使用的连接放回到连接池中)。但却不要及时关闭数据库连接,why?——答案在第二个问题中,将会做出解答。
2.数据库连接打开与关闭,(为了确保'连接用时打开用完立即关闭'的原则),要在每次数据库操作时都去打开和关闭连接吗?
——在给出解答之前,先看如下代码("配餐系统" 中 分页查询的方法)
- 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;
 - //是否需要按营养素排序
 - 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();
 - //得到信息总条数
 - 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 按营养素排序
 - 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;
 - }
 
大家看后,会发现此方法中,有以下几点值得注意:
a.有些代码后有 "//[*]“——此用于标识所在行代码是执行数据库操作,方便大家能清楚的知道 try/catch 代码块中有几处数据库(连接)操作
b.DBHelper.OpenCon();和DBHelper.CloseCon(); ——大家大概可以知道:此try/catch 代码块中只有一次数据库打开和关闭,——事实上也确实只有一次。再看下其中涉及(调用)到的部分方法:
- 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] (此方法需要 手动(即调用OpenCon(); CloseCon();方法)打开和关闭连接)
 - ///
 - ///
 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循环代码块中 有两次GetFlName方法(此方法最终是对ExecuteScalar_Object_Other方法)的调用,这样如果是reader中有20条记录, 并且在ExecuteScalar_Object_Other方法内部(查询)操作开始前打开连接,结束时关闭连接,此while循环代码块执行完——将可能有20*2=40次的数据库连接打开与关闭操作,假设:每次数据库连接打开与关闭操作需要0.1s的时间,那么此while循环代码块将需要至少0.1*40=4s的时间执行,再加上其它的查询或更多更频繁的数据库操作, 效率就可想而知。【这个得回到在此文一开始所说的,“有些东西你以为弄清楚明白了,其实未必”。在之前未做winform开发(确切的说是 没有使用access数据库时),数据库操作方法,都是如下方法([旧DBHelper类中的]:即在方法内部,连接即开即关。也是网上很多通用DBHelper数据库操作类中的写法),因为在项目中用的都是mysql,sqlserver这种大型的数据库, 即使不用连接池,数据量不大的情况下,查询等速度都比access数据库要快的多,那时还感觉自己略作优化过的DBHelper类已经够用了,效果也还不错。但是在做winform"配餐系统"开发时,用的是access数据库,还用之前的DBHelper类,也是做GetFoodInfosList方法中相同的查询操作(当时还没考虑分页),问题就暴露出来了——只查询10条左右的记录,界面却等待了3s左右,结果才(卡)出来。 出现了问题,只能查看代码思考解决问题:数据库操作代码还是之前项目中的DBHelper类中,为什么会查询速度如此之慢呢?后慢慢想明白和知道:access数据库跟mysql,sqlserver等大型的数据库相比,性能差了很多,数据库性能差,而也不考虑换用其它的数据库,只能在代码上做优化,于是修改了DBHelper类,类似于重构了部分方法——以适应不同情况下的需要。】
[旧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();
 - }
 - }
 
好了,到这儿,可以对以上两个问题一起做个答复,阐明此文的关键点:数据库连接的打开和关闭,要在当前可见范围内或代码块中 数据库操作开始前 打开连接,在无需(或者说***一个)数据库操作后 关闭连接,举例:在一个方法或代码块中,如上GetFoodInfosList方法;在一个事件中,如:一个按钮的点击事件中:可能会执行n次数据库 增删改差等操作....
结束语:应该是***次写这么长的技术文章,写的比较艰难,呵呵...,感觉把自己知道的东西想写的让别人能很容易看懂且不丢失自己想说的,不是一件容易的事。后附的是***的DBHelper类(里面还有一些地方可以或需要优化),希望路过的朋友能多提意见或交流你的看法!
***的DBHelper类:
- using System;
 - using System.Collections.Generic;
 - using System.Text;using System.Data.OleDb;using System.Data;
 - namespace ZhiyiHelper
 - {
 - public partial class DBHelper
 - {
 - /**
 - * 以下的方法需要在调用的可见区域内:手动(即调用OpenCon(); CloseCon();方法)打开和关闭连接
 - * 方法注释中有[Notice Con] 或 [Notice Connection] 或方法名中含有“_Other”,则调用的是以下的方法
 - * */
 - #region 数据库操作方法
 - ///
 - /// 执行增,删,改命令的方法
 - ///
 - /// 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和数据库连接都需要显示关闭]
 - ///
 - /// 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;
 - }
 - ///
 - /// 执行多条SQL语句,实现数据库事务。
 - ///
 - /// 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);
 - }
 - }
 - ///
 - /// 关闭和释放数据读取器
 - ///
 - /// 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 基础方法
 - ///
 - /// 获取连接字符串的属性
 - ///
 - private static string Connstr
 - {
 - get
 - {
 - if (connstr == String.Empty)
 - {
 - connstr = ConfigHelper.GetConnectionStringsString("accessConSql");
 - connstr = GetConnString();
 - }
 - return connstr;
 - }
 - }
 - ///
 - /// 得到数据库连接方法
 - ///
 - ///
 数据库连接 returns> - private static void Getconn()
 - {
 - if (conObject == null)
 - conObject = new OleDbConnection(Connstr);
 - }
 - ///
 - /// 获得并打开数据库连接方法
 - ///
 - ///
 returns> - public static void OpenCon()
 - {
 - Getconn();
 - if (conObject.State == ConnectionState.Open)
 - return;
 - if (conObject.State != ConnectionState.Closed)
 - conObject.Close();
 - conObject.Open();
 - }
 - ///
 - /// 关闭数据库连接方法
 - ///
 - public static void CloseCon()
 - {
 - if (conObject != null && conObject.State != ConnectionState.Closed)
 - conObject.Close();
 - }
 - #endregion
 - #region 数据库操作方法
 - public static int GetMaxID(string FieldName, string TableName)
 - {
 - string strsql = "select max(" + FieldName + ") from " + TableName;
 - try
 - {
 - return GetScalar(strsql);
 - }
 - &n
 分享名称:浅谈配餐系统中数据库连接打开与关闭
文章转载:http://www.csdahua.cn/qtweb/news7/482107.html网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网