数据库连接,这还用说,都会接触到啊,说的这是这个经常见的数据库连接。
1 |
Data
Source=.;Initial Catalog=test;Persist Security Info=True;User
ID=testuser;Password=123456;Min Pool Size=10;Max Pool
Size=150;Connection Lifetime=10 |
这谁不明白啊,这里要说的就是
Min Pool Size=10;Max Pool Size=150;Connection Lifetime=10
这里就说到 数据库连接池
了,默认是启用的,以上的属性就是配置这个连接池的。这也就意味着,当你的页面发送数据库请求的时候,不一定就非要创建数据库连接,而可能是从已存在连接
池里,激活一个的连接来处理你的请求的;同样,当你代码中调用Close显式关闭数据库连接的时候,也不一定就是真的关闭数据库连接了,如果当前连接池中
没有满足Min Pool Size要求的连接时,它只是返回到连接池,等待下一个命令来激活它。
通过
可以查看你当前连接数
连接池是怎么按照你的配置如何工作呢??
当第一次连接请求到来时,它会在很短的时间内创建Min Pool
Size指定的连接,尽管你的并发请求数可能远没达到这个数目。当并发请求数低于这个值,这以后将不会有连接的的创建和关闭,除非你关闭应用程序;并发请
求数目大于这个最小值时,就会创建连接,并发请求数大于Max Pool
Size最大值时,这个请求将进入等待队列,等待空闲连接,如果达到应用程序或者数据库限制的时 间还没被处理,就将返回连接超时的异常。
这原理谁不懂啊,是的,程序正常的时候是这样,当程序不正常的时候是什么样呢。。正常的程序:凡是操作数据库的,操作完毕之后都有显式的调用
Close()或者Dispose()关闭连接。下面做个试验,同样下面提供的方法,可以验证你的应用程序是否存在没有关闭的连接。本人也是基于这个需
求,才做这些试验的。
现如今的程序,涉及数据操作的都是封装好啊,是的,像dataset,datatable等reader以外的操作,都是在数据库操作类处都关闭了。嗯,
是的,但是reader,就只有在开发人员用完之后显示关闭了,这就可能由开发人员的素质决定了。不要告诉我,你根本就不用reader,呵呵,那这篇文
章跟你没关系了。
就以reader来开始实验,我们把Min Pool Size设为1.
首先是正常的程序:
01 |
using (SqlDataReader reader = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from protuct order by id desc" )) |
05 |
Response.Write(reader[ "Name" ].ToString()); |
08 |
using (SqlDataReader reader2 = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from users order by userid desc" )) |
10 |
while (reader2.Read()) |
12 |
Response.Write(reader2[ "userName" ].ToString()); |
这段程序放在一个页面里,无论你怎么刷或者多少人同时请求这个页面,待请求处理结束后,通过sp_who查看到的,还是那一个。知道这为什么叫正常的程序了吧,符合正常推理,哈哈。
以下是有问题的程序:
01 |
SqlDataReader reader3 = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from users order by userid asc" ); |
02 |
while (reader3.Read()) |
04 |
Response.Write(reader3[ "userName" ].ToString()); |
06 |
SqlDataReader reader4 = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from protuct2 order by id asc" ); |
07 |
while (reader4.Read()) |
09 |
Response.Write(reader4[ "Name" ].ToString()); |
11 |
SqlDataReader reader5 = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from protuct order by id desc" ); |
12 |
while (reader5.Read()) |
14 |
Response.Write(reader5[ "Name" ].ToString()); |
16 |
SqlDataReader reader6 = Maticsoft.DBUtility.DbHelperSQL.ExecuteReader( "select top 1 * from users order by userid desc" ); |
17 |
while (reader6.Read()) |
19 |
Response.Write(reader6[ "userName" ].ToString()); |
可以看到,reader没有显式关闭,为了看效果,多放了几个。
首先,我先一个人正常的刷一下,页面加载完毕后,通过sp_who查看,连接有4个,状态是sleeping,wait
command,大于Min Pool
Size了,不正常。我如果再刷一下,你猜会是几个,8个??大于4个??再一次次正常的刷,结果还是4个????说明连接执行完毕后会自动返回连接池,
没有关闭的请求,就存活了下来,但是有执行操作的请求时,它们依然可以被激活来执行操作。哇哈哈,那岂不是很爽,没有显式关闭连接不会造成任何不良的影响
啊。哈哈,但是,没有显式关闭并不代表不关闭啊,根据.net垃圾收集的工作原理,我们知道任何对象在离开它的工作范围之后就成了垃圾,等待被回收,回收
的过程中,回收管理器发现对象实现了IDipose(),就会再次激活这个对象,调用它的Dispose(),然后再次成为垃圾,最终被回收。
Dispose()调用的时候,是不确定的,因此,连接池中多余的连接也会在未来的某个时间关闭,那么就有可能造成程序的不稳定,因为这个连接可能此时已
经被激活处理其它请求,又可能被后来的请求已显式关闭等等,也或许微软已通过某种机制让上述担心成为了多余。但是不正常代码,影响远不止这些。。。。。
请注意前面是一次次正常的刷新,也就是我自己等页面出来以后,再刷新页面,下面我强制按住F5,让页面连续刷新,再次通过sp_who
查看,结果大吃一惊,此时sleeping的连接,达到了几十个,如果很多人呢同时访问呢,那连接池很快就会被这占满,不稳定的影响,很快就会被放大很多
倍。因些如何判断你的应用程序存在未关闭的连接,在访问高峰期或者自己模拟大量的并发请求,查看如果状态是sleeping的连接大于你设定的Min Pool Size值,肯定就是存在了。
下面再说说Connection Lifetime
官方解释:每当一个连接使用完后释放回连接池,如果当前时间减去该连接建立的时间的值大于这个参数设定的值(秒),该连接被销毁。0表示lifetime没有上限。
根据表面意思,没显式关闭的连接也会在这个值指定的时间来临时关闭,那太好了,管它reader关没关呢,设个较小lifttime不得了。但是令人疑惑
的是,我把此值设为1,不正常代码的产生的多余连接并没有在1秒后销毁,而是等待一个不太确定的时间,这个可能就是垃圾收集来临的时间,同样正常代码情况
下,将此值设为60,显式调用的如果超出Min Pool Size的连接会被立即关闭,在Min Pool
Size范围内的连接一直存活。这么看来此值没一点作用啊。
搜索了搜索发现有篇文章提到了作用:
Connection Lifetime作用(数据库群集)
实验结束,再一次用事实证明连接一定要显式关闭,同样提供了一个简单方法查看我们的程序是不是存在未关闭的连接。
http://www.cnblogs.com/forcertain/archive/2011/01/20/1939808.html