来cnblogs快一年了,斗胆发一篇在首页,
这篇文章主要写解决一个网上答案不能解决自己问题的时候,解决问题的整个流程,
如果大家觉得这个没价值,还请管理员帮忙撤销发首页
先谢谢各位了。
一年前帮学校做了一个就业信息管理系统,
当时图热闹,觉得虽然说学校人不是很多,但是看惯了大家对GridView的性能的漫骂,
抱着练手的想法,自己用repeater 代替了GridView 来做数据显示
之后系统采用三层架构设计。。。。
之后做好了在自己本机上怎么测都没毛病,觉得差不多了
就向学校申请服务器架设,
结果没用几天,出毛病了, 老是提示
“超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。 ”
ok,google 了下,这个一般是因为DbConnection 开启了之后忘记关闭的(参见http://www.cnblogs.com/peak/archive/2009/04/24/1443116.html)
自己本身写了个DbHelper,改起来应该很快,
结果一看,雷到了,原来我在DbHelper里面已经关闭了啊
/// <summary>
/// 执行查询语句,返回DataSet
/// </summary>
/// <param name="SQLString">查询语句</param>
/// <returns>DataSet</returns>
public static DataSet Query(string SQLString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet ds = new DataSet();
try
{
connection.Open();
SqlDataAdapter command = new SqlDataAdapter(SQLString, connection);
command.Fill(ds, "ds");
}
catch (System.Data.SqlClient.SqlException ex)
{
throw new Exception(ex.Message);
}
finally
{
connection.Close();
}
return ds;
}
}
百思不得其解,最后没办法,临时想了个方案,关闭“连接池”
在web.config 中写入
connectionString="Data Source=.\sqlexpress;Initial Catalog=YTJY;User ID=xxx;Password=xxx;pooling=false"
懂行的一看就知道是笨办法。。。
用了一段时间,貌似不报那个错了,所以就没注意了
可是,
今年6月,这个错误又华丽的出现了。
原来跑就业那台服务器因为项目需要,又装了个Oracle
额,抱歉,我一直说服务器,实际上是台pc机,联想的,配置忘记了,就记得是512 的内存后来换成1G的了,07年买的菠萝机
内存直接常年1G 占满
最后没办法,学校传说去采购了9k 的服务器(真的服务器了)
虽然马上就华丽的本科毕业(还几天就答辩。。。)
但是如果程序放新的服务器上还是不得行,校方直接毕业设计挂我我不是惨死。。。。。
没办法,琢磨着解决问题吧。。。
研究错误提示
超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
反复读这句话,连接池我已经取消了啊,相当于每次读数据都是从数据库里申请链接,没有连接池的概念了哈
终于,发现一个很抑郁的事情
我理解这句话理解错了,或者,微软没描述好这句话的意思。
这个错误提示的核心应该是超时时间已到
而不是“尚未从池中获取连接”
引起这个错误的原因只是数据库连接超时了,微软关于为什么超时的解释是“尚未从池中获取连接”,但是问题的本质,还是连接数据库超时
回想下大二学的数据库的知识,貌似数据库超时主要原因有
1、死锁
2、申请的链接数过多导致数据库来不及响应
3、网络连接错误。。。
我第一个排除的就是死锁,因为在出错的操作里面,没有设计到任何关于“增删改”的操作,没有失误的参与,仅仅是简单的Select,应该不可能出现死锁
第二个排除的是链接错误,因为IIS和SQLServer存在一台机器上,应该不会。。。
由此,估计是申请的连接数过多而导致了 数据库超时,
ok,现在的目标就是,检测系统到底打开了多少个数据库连接。
ok,由于是通宵作战,不在实验室,就跑的本机,
机器撇,就装了个Express 版本的SQLServer 2005
没有自带的工具
只好网上google 了下,发现了个不错的监视软件,free。。。。
叫SqlExpressProfiler.... http://code.google.com/p/sqlexpressprofiler/
用来监视数据库打开的链接,
小小的配置一下
因为我需要知道执行了多少条记录,于是打开AuditLogin 选项(因为每次执行都要数据库登录下。。。。)
加断点跑跑
不跑不知道,一跑吓一跳。。。。。
这是我打开一个页面的记录。。。。
页面为
建立的数据链接为
看一下右面的滚动条就知道了。。。。链接数据库50次左右。。。。
ok,问题顿时就明朗了。
打开一个页面访问数据库上50次,
如果有一个老师跑来审核数据,之后没事点“下一页”
短时间内,可以打开超过200个数据库连接
之后这几天刚好是教委填报数据的时候,
几乎所有辅导员都在审核这些信息,
假设有5个辅导员同时看这些资料,
那么短时间内,就有1000次链接数据库。。。。。。
我的妈呀。。。。让菠萝机上1000次,连的上数据库才怪。
ok,知道问题所在了,下面就非常容易了
加断点,单步走,每走一步看下数据库连接数
没过几分钟,就查到了问题所在,
问题来自于绑定分页的地方。。
我不知道那根经不对,写了这样一个语句。。。。。。。
for (int i = 0; i < Bll_JiuyeList.getPageCount(PAGESIZE, getStrWhere()); i++)
{
DropDownList_Jump.Items.Add((i + 1).ToString());
}
DropDownList_Jump.SelectedValue = "1";
想必大家一眼就看到了这个错误,
for语句中 判断是每循环一次都要执行的,然而我在判断i 的时候竟然将判断条件写成了调用“逻辑业务层”,逻辑业务层调用数据链路层,
这样直接导致了循环有多少次,就查了多少次数据库。。。。。。
将这个地方更正,连接数立马下降到5个以内。。。。
至此,遗留了1年的bug,就此解决。。。。。。
ok,总结下吧。
---------------------------------------------------
第一,要相信科学。当出现那个“超时时间已到”的提示,之后google后按照方法做,还是不行的时候,要坚信,这是会解决的。
第二,临时方法靠不住。临时方法临时解决问题,只有找到处问题的根源,才能真正的解决问题。
第三,for语句中的判断条件,一定要慎重,再慎重,除非确定必要,否则坚决不在此使用任何函数,特别是可能操作数据库的函数
---------------------------------------------------
恩恩,写完了,希望本文能给您带来一些收获,
再次感谢您看完这篇文章,也希望多多与大家交流,
第一次发在首页,压力很大,但是真的很想与大家分享这次经验
如果不适合放首页,麻烦管理员撤下,谢谢了