连接池分析 pooling

在测试某个项目时发现,在双线路应用中,两条线路都指向同一数据库服务器

线路A (191.1.1.100) 

线路B(198.1.1.100)

实际测试发现,如果先使用A连接,网络A断开后再使用B连接 正常可用,这时再返回A连接,就会报错,确认后继续执行该操作又正常了。

服务器返回错误提示:

"在向服务器发送请求时发生传输级错误。(provider:TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。)"

 

在查询大量资料后发现,只要在数据库连接字符串中加入 pooling = false 就不会报错,其原因是启用了连接池技术。

 

==========================================================================================================

相关资料:

1. 连接池允许应用程序从连接池中获得一个连接并使用这个连接,而不需要为每一个连接请求重新建立一个连接。一旦一个新的连接被创建并且放置在连接池中,应用程序就可以重复使用这个连接而不必实施整个数据库连接创建过程。 当应用程序请求一个连接时,连接池为该应用程序分配一个连接而不是重新建立一个连接;当应用程序使用完连接后,该连接被归还给连接池而不是直接释放。

如何实现连接池
pooling = true ( 默认为开启 true)
确保你每一次的连接使用相同的连接字符串(和连接池相同);只有连接字符串相同时连接池才会工作。如果连接字符串不相同,应用程序就不会使用连接池而是创建一个新的连接

2. 当polling  = false 时 ,应用程序每次连接时为每一个连接请求重新建立一个连接

 

 

优点

        使用连接池的最主要的优点是性能。创建一个新的数据库连接所耗费的时间主要取决于网络的速度以及应用程序和数据库服务器的(网络)距离,而且这个过程通常是一个很耗时的过程。而采用数据库连接池后,数据库连接请求可以直接通过连接池满足而不需要为该请求重新连接、认证到数据库服务器,这样就节省了时间。

缺点

       数据库连接池中可能存在着多个没有被使用的连接一直连接着数据库(这意味着资源的浪费)。

技巧和提示

1.   当你需要数据库连接时才去创建连接池,而不是提前建立。一旦你使用完连接立即关闭它,不要等到垃圾收集器来处理它。

2.   在关闭数据库连接前确保关闭了所有用户定义的事务。

3.   不要关闭数据库中所有的连接,至少保证连接池中有一个连接可用。如果内存和其他资源是你必须首先考虑的问题,可以关闭所有的连接,然后在下一个请求到来时创建连接池。

 

 


连接池FAQ
Q:   何时创建连接池?
A:    当第一个连接请求到来时创建连接池;连接池的建立由数据库连接的连接字符创来决定。每一个连接池都与一个不同的连接字符串相关。当一个新的连接请求到来时如果连接字符串和连接池使用的字符串相同,就从连接池取出一个连接;如果不相同,就新建一个连接池。

Q:    何时关闭连接池? 
A:    当连接池中的所有连接都已经关闭时关闭连接池。

Q:   当连接池中的连接都已经用完,而有新的连接请求到来时会发生什么?
A:当连接池已经达到它的最大连接数目时,有新的连接请求到来时,新的连接请求将放置到连接队列中。当有连接释放给连接池时,连接池将新释放的连接分配给在队列中排队的连接请求。你可以调用close和dispose将连接归还给连接池。

Q:   Close()和Dispose()有什么不同,我应该用哪一个好?
A:   它们做的是同一件事,你可以调用他们中的任意一个,或两个同时使用.

Q:   与close()相比,connection.dispose()会将连接些移除吗?
A:   不会


Q:   我应该如何允许连接池?
A:   对于.NET应用程序而言,默认为允许连接池。(这意味着你可以不必为这件事情做任何的事情)当然,如果你可以在SQLConnection对象的连接字符串中加进Pooling=true;确保你的应用程序允许连接池的使用。

Q:   我应该如何禁止连接池?
A:   ADO.NET默认为允许数据库连接池,如果你希望禁止连接池,可以使用如下的方式:
1) 使用SQLConnection对象时,往连接字符串加入如下内容:Pooling=False;
2) 使用OLEDBConnection对象时,往连接字符串加入如下内容:OLE DB Services=-4;

不要把Poooling=False

坦白的说,如果你将pooling设为关闭状态,你当然不会再碰到超时异常,可怕的是你的应用程序性能将大大降低,而你的连接仍然处于泄漏状态.

不要把Connection LifeTime=1

这不是一个能清除异常的方法,但它可能是最接近的一个解决方法.你想告诉我们的是将所有的连接超过一秒钟的连接都通通抛弃(正常的生命周期结束应该是在connetcio.close()后).我个人认为这种方法上关闭连接池没什么两样.除非你是在使用数据库的集群,否则你不应设置连接周期来达到目的.


不要将 Connection TimeOut=40000


非常愚蠢的选择,你这是在告诉我们在抛出一个超时异常之前,你在无限地等待一个连接转变为可用的.幸亏在ASP.NET中将会在三分钟之后取消一个进程.


不要将Max PoolSize=4000;
如果你将连接池的最大数设置到足够大的时候,你最终会将这异常停止.但在另一方面,你将占用了你的应用程序中才是真正需要的巨大的连接资源,这种做法只能饮鸠止渴.

======================================================================================================================

下面分2种情况进行讨论。
1,Client端的windows form application通过ADO.Net直接访问后台Database。
 
查看大图
SqlServer DirectConnection

我认为在这种情况下,每一个Client端和Database之间都存在一个连接池。通过设置ConnectiongString的Max Pool Size和Min Pool Size属性来验证。
如Max Pool Size = 5, Min Pool Size = 3, 通过SQL Server的SP_WHO2可以检测导如下结果:
启动1个Client端的Windows form application:application和SQL Server之间存在3个connection。
启动2个Client端的Windows form application:application和SQL Server之间存在6个connection。
启动3个Client端的Windows form application:application和SQL Server之间存在9个connection。
 
由此可见,每一个Client端和SQL Server之间都存在一个连接池,否则9个connection已经超出了Max Pool Size的设定。
 
2,Client端的application不直接通过ADO.Net来访问后台Database,而是通过IIS Server来同后台Database Server打交道。
至少有如下2种情况:
(1)Client通过IE访问部署在IIS中的web application,web application中的Data Access Class进一步访问后台Database Server.
(2)Client端的windows form application访问部署在IIS中的Remote Object,Remote Object进一步访问后台Database Server.
 
查看大图
SqlServer InDirectConnection
下面进行同样的测试:通过设置ConnectiongString的Max Pool Size和Min Pool Size属性来验证。
如Max Pool Size = 5, Min Pool Size = 3, 通过SQL Server的SP_WHO2可以检测导如下结果:
启动1个Client端的Web form application:application和SQL Server之间存在3个connection。
启动2个Client端的Web form application:application和SQL Server之间存在3个connection。
启动3个Client端的Web form application:application和SQL Server之间存在3个connection。
调用由IIS承载的Remote Object,结果类似。只是在未启动Client端之前,发现在Remote Object与Database Server之间已经存在一个connection。
由此可见,对同一个application而言,IIS Server与Database Server之间只有存在一个连接池,与Client端的多少没有关系。


3,连接池小节
根据上面的测试结果,显然第二种情况更有利于减少无用的连接数量,提高Database Server的性能。关于.Net Remoting技术及其性能问题,可以参考如下的Reference连接,这里就不讨论了。
另外,本文是个人关于连接池的一些见解,如果观点有不正确之处,希望不要误导各位。欢迎各位在此发表意见。同意的说赞同,不同意的请提出您的看法。谢谢。
Reference Links:
(1) MSDN, ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconconnectionpoolingforsqlservernetdataprovider.htm
(2) Microsoft .NET Remoting:技术概述, http://www.microsoft.com/china/MSDN/library/NetFramework/default.mspx
(3) 性能比较:.NET Remoting 与 ASP.NET Web 服务, http://www.microsoft.com/china/msdn/archives/library/dnbda/html/bdadotnetarch14.asp
========================原文结束,开可以参考另外一篇文章:NET 连接池救生员
原文的一些补充观点:


连接的创建和获取:
Q: 如果我最大连接池是5个,那么,在我的程序中,每次访问,我都会使用New一个连接,然后Open,使用以后,然后Close,那么在每次New的时候,会不会创建连接,?
A: 在每次New的时候,如果connection pool中有空闲的连接,则不会创建新连接,否则会创建。
如果超过最多连接数,还能发出New的请求,但是该请求会放入队列,直到connection pool中有空闲连接或连接请求超时。
连接的效率问题:


Q: 要是可以对连接进行控制的话,应该怎么控制,很简单,我现在每次使用数据库访问时,都会New并close,我是担心这样的效率是不是会很低啊,想在连接上提高效率,要怎么操作呢?
A: 使用connection pool时,New并不一定会创建新的连接,如果connection pool中有空闲连接,直接拿来就用。
close也只是将连接放入connection pool,供后续请求使用。因此不会有效率问题。
连接的存活时间:
当连接返回到池中时,将对它的创建时间和当前时间进行比较,如果时间间隔超过由 Connection Lifetime 指定的值(以秒为单位),则会毁坏该连接。在聚集配置中可以使用它来强制在运行服务器和刚联机的服务器之间达到负载平衡。
如果值为零 (0),则将使池连接具有最大的超时期限。默认值为0
SqlConnection.Close和.Dispose的比较:
sqlconnection.close和.dispose的相同地方是:
dispose肯定调用了close,所以close里面有做的事情,dispose都包括
dispose还做了其他的资源的释放,这样在GC第一次回收的时候,省却了dispose的步骤,加快了内存资源的回收速度。
如果没有调用dispose,GC将在第一次回收先做dispose。
如果程序频繁做new sqlconnection(),然后很快就做close并且不再使用这个connection(例如一些com+/asp.net/web service的程序),而且又不做dispose,那么随着这个程序被多次调用,被分配但未能尽快释放的系统资源(通常是内存)会有很多,GC被迫回收的次数也相应增多,系统的整体效率就会变低(GC回收的时候是所有.net程序都暂停,等GC回收跑完才可以继续,造成其他程序也受到影响)。所以对于这种情况,做dispose好。
但如果其他情况,例如Winforms的client,那么没有所谓。
最近发现本站有时候会出现连接不上服务器的现象,通过sp_who查看数据库连接时,发现网站应用程序占用了比较多的连接数,当连接数达到一定数量后,网站就会出现连接不上数据库的错误。那么可以肯定,网站出现错误的原因,是数据库连接没有及时释放的缘故——或者是开辟了太多的连接。网站的数据库访问逻辑没有集中在一个数据库访问类中,而是在用到的时候建立,用完了关闭。那么这种情况是否跟上文讲的第一种情况相同呢?上文的第一种情况应该是针对winform应用程序来说的。但是本站的程序没有想上文说的第二种情况,把数据访问集中在一个数据访问类中。这个问题有待实践来验证。


 

~

猜你喜欢

转载自blog.csdn.net/gtosky4u/article/details/48969505