ADO.NET中SQL Server数据库链接池

实际上,大多数应用程序仅使用一个或几个不一样的链接配置。 这意味着在执行应用程序期间,许多相同的链接将反复地打开和关闭。 为了使打开的链接成本最低,ADO.NET 使用称为链接池的优化方法。算法

链接池减小新链接须要打开的次数。 池进程保持物理链接的全部权。 经过为每一个给定的链接配置保留一组活动链接来管理链接。 只要用户在链接上调用 Open,池进程就会检查池中是否有可用的链接。 若是某个池链接可用,会将该链接返回给调用者,而不是打开新链接。 应用程序对该链接调用 Close 时,池进程会将链接返回到活动链接池集中,而不是真正关闭链接。 链接返回到池中以后,便可在下一个 Open 调用中重复使用。数据库

只有配置相同的链接能够创建池链接。 ADO.NET 同时保留多个池,每一个配置一个池。 链接由链接字符串以及 Windows 标识(在使用集成的安全性时)分为多个池。 还根据链接是否已在事务中登记来创建池链接。安全

池链接能够显著提升应用程序的性能和可缩放性。 默认状况下,ADO.NET 中启用链接池。除非显式禁用,不然,链接在应用程序中打开和关闭时,池进程将对链接进行优化。 还能够提供几个链接字符串修饰符来控制链接池的行为。服务器

池的建立和分配网络

在初次打开链接时,将根据彻底匹配算法建立链接池,该算法将池与链接中的链接字符串关联。 每一个链接池都与一个不一样的链接字符串相关联。 打开新链接时,若是链接字符串并不是与现有池彻底匹配,将建立一个新池。 按进程、按应用程序域、按链接字符串以及(在使用集成的安全性时)按 Windows 标识来创建池链接。 链接字符串还必须是彻底匹配的;按不一样顺序为同一链接提供的关键字将分到单独的池中。架构

在如下 C# 示例中建立了三个新的 SqlConnection 对象,可是管理时只须要两个链接池。 注意,根据为 Initial Catalog 分配的值,第一个和第二个链接字符串有所不一样。性能

 using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=Northwind"))   
             {  
                 connection.Open();        
                 // Pool A is created.  
             }  
            using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=pubs")) 
            { 
                connection.Open();      
                // Pool B is created because the connection strings differ. 
            }  
            using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=Northwind")) 
            { 
                connection.Open();       
                // The connection string matches pool A.  
            }

若是 MinPoolSize 在链接字符串中未指定或指定为零,池中的链接将在一段时间不活动后关闭。 可是,若是指定的 MinPoolSize 大于零,在 AppDomain 被卸载而且进程结束以前,链接池不会被破坏。 非活动或空池的维护只须要最少的系统开销。测试

注意:优化

当出现故障转移等错误时,会自动清除池。ui

添加链接

链接池是为每一个惟一的链接字符串建立的。 当建立一个池后,将建立多个链接对象并将其添加到该池中,以知足最小池大小的要求。 链接根据须要添加到池中,可是不能超过指定的最大池大小(默认值为 100)。 链接在关闭或断开时释放回池中。

在请求 SqlConnection 对象时,若是存在可用的链接,将从池中获取该对象。 链接要可用,必须未使用,具备匹配的事务上下文或未与任何事务上下文关联,而且具备与服务器的有效连接。

链接池进程经过在链接释放回池中时从新分配链接,来知足这些链接请求。 若是已达到最大池大小且不存在可用的链接,则该请求将会排队。 而后,池进程尝试从新创建任何链接,直到到达超时时间(默认值为 15 秒)。 若是池进程在链接超时以前没法知足请求,将引起异常。

警告: 咱们强烈建议您在使用完链接后老是将其关闭,以使链接返回到池中。要关闭链接,可使用 Connection 对象的 CloseDispose 方法,也能够经过在 C# 的 using 语句中或在 Visual Basic 的 Using 语句中打开全部链接。 不是显式关闭的链接可能不会添加或返回到池中。

移除链接

若是链接长时间空闲,或池进程检测到与服务器的链接已断开,链接池进程会将该链接从池中移除。 注意,只有在尝试与服务器进行通讯以后才能检测到断开的链接。 若是发现某链接再也不链接到服务器,则会将其标记为无效。 无效链接只有在关闭或从新创建后,才会从链接池中移除。

若是存在与已消失的服务器的链接,那么即便链接池管理程序未检测到已断开的链接并将其标记为无效,仍有可能将此链接从池中取出。 这种状况是由于检查链接是否仍有效的系统开销将形成与服务器的另外一次往返,从而抵消了池进程的优点。 发生此状况时,初次尝试使用该链接将检测链接是否曾断开,并引起异常。

清除池

ADO.NET 2.0 引入了清除池的两种新方法: ClearAllPools 和 ClearPool。 ClearAllPools 清除给定提供程序的链接池,ClearPool 清除与特定链接关联的链接池。 若是在调用时链接正在使用,将进行相应的标记。 链接关闭时,将被丢弃,而不是返回池中。

使用链接字符串关键字控制链接池

下表列出了 ConnectionString 内链接池值的有效名称。有关更多信息,请参见 SQL Server 链接池 (ADO.NET)。

Connection Lifetime

0

当链接被返回到池时,将其建立时间与当前时间做比较,若是时间长度(以秒为单位)超出了由 Connection Lifetime 指定的值,该链接就会被销毁。这在汇集配置中颇有用(用于强制执行运行中的服务器和刚置于联机状态的服务器之间的负载平衡)。

零 (0) 值将使池链接具备最大的链接超时。

Connection Reset

'true'

肯定从池中提取数据库链接时是否重置数据库链接。对于 SQL Server 7.0 版,设置为 false 可避免获取链接时再有一次额外的服务器往返行程,但须注意此时并未重置链接状态(如数据库上下文)。

只要不将 Connection Reset 设置为 false,链接池程序就不会受到 ChangeDatabase 方法的影响。链接在退出相应的链接池之后将被重置,而且服务器将移回登陆时数据库。不会建立新的链接,也不会从新进行身份验证。若是将 Connection Reset 设置为 false,则池中可能会产生不一样数据库的链接。

Enlist

'true'

当该值为 true 时,池程序在建立线程的当前事务上下文中自动登记链接。可识别的值为 true、false、yes 和 no。

Load Balance Timeout

0

链接被销毁前在链接池中生存的最短期(以秒为单位)。

Max Pool Size

100

池中容许的最大链接数。

Min Pool Size

0

池中容许的最小链接数。

Pooling

'true'

当该值为 true 时,系统将从适当的池中提取 SQLConnection 对象,或在须要时建立该对象并将其添加到适当的池中。可识别的值为 true、false、yes 和 no。

 

 

 

从深蓝居的博客上找到的描述:

前几天同事问我一个问题,一种CS架构的程序,直接把SQL Server做为服务端,每一个客户端直接链接数据库操做(kay注:S2的cs项目就是这种架构),若是客户端打开的数量过多时SQL Server的链接数将会特别高,数据库端造成性能瓶颈,这种状况下怎么办?想了想,形成这种状况的缘由是ADO.NET的内部机制形成的。ADO.NET中为了提升性能,因此使用了链接池,这样每一个请求就没必要都建立一个链接,而后认证,而后执行SQL,而是从链接池中直接取出链接执行SQL,执行完成后也并非真正关闭链接,而是将该链接从新放回链接池中。若是有100个客户端,每一个客户端在使用一段时间后链接池中保存了10个链接,那么在这种状况下,即便不在客户端作任何操做,SQL Server上都有1000个链接,这样不出性能问题才怪。

既然是链接池的问题,那么我就针对该问题想到了2个解决办法:

1.关闭ADO.NET的链接池,每次执行SQL时都是新建一个链接执行,而后关闭。这样作将使数据查询有所减慢(每次都创建链接,每次都认证,固然会慢了),不过这个慢是毫秒级的,通常感受不到的,可是若是一个操做就涉及到几百个SQL语句的状况可能会明细感受到减慢。修改方法特别简单,都不用修改代码,在数据库连接字符串中加入Pooling=False;便可。

2.修改架构,这种CS架构除了性能问题外还会出现其余的好比安全上的问题。能够将直接连数据库的方法改为链接服务,这其中可使用Remoting、Web服务等,固然如今能够统一用WCF了。这样作就只有服务程序去链接数据库,而客户端只链接服务程序,这样就不会出现链接池形成的瓶颈。不过这样作代码修改量很大,若真要改仍是很痛苦的。

如下是网上找到的一篇介绍ADO.NET链接池的文章,感受不错。

链接池容许应用程序从链接池中得到一个链接并使用这个链接,而不须要为每个链接请求从新创建一个链接。一旦一个新的链接被建立而且放置在链接池中,应用程序就能够重复使用这个链接而没必要实施整个数据库链接建立过程。

当应用程序请求一个链接时,链接池为该应用程序分配一个链接而不是从新创建一个链接;当应用程序使用完链接后,该链接被归还给链接池而不是直接释放。

如何实现链接池

确保你每一次的链接使用相同的链接字符串(和链接池相同);只有链接字符串相同时链接池才会工做。若是链接字符串不相同,应用程序就不会使用链接池而是建立一个新的链接。

优势

使用链接池的最主要的优势是性能。建立一个新的数据库链接所耗费的时间主要取决于网络的速度以及应用程序和数据库服务器的(网络)距离,并且这个过程一般是一个很耗时的过程。而采用数据库链接池后,数据库链接请求能够直接经过链接池知足而不须要为该请求从新链接、认证到数据库服务器,这样就节省了时间。

缺点

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

技巧和提示

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

2. 在关闭数据库链接前确保关闭了全部用户定义的事务。

3. 不要关闭数据库中全部的链接,至少保证链接池中有一个链接可用。若是内存和其余资源是你必须首先考虑的问题,能够关闭全部的链接,而后在下一个请求到来时建立链接池。

链接池FAQ

1. 什么时候建立链接池?

当第一个链接请求到来时建立链接池;链接池的创建由数据库链接的链接字符创来决定。每个链接池都与一个不一样的链接字符串相关。当一个新的链接请求到来时若是链接字符串和链接池使用的字符串相同,就从链接池取出一个链接;若是不相同,就新建一个链接池。

2. 什么时候关闭链接池?

当链接池中的全部链接都已经关闭时关闭链接池。

3. 当链接池中的链接都已经用完,而有新的链接请求到来时会发生什么?

当链接池已经达到它的最大链接数目时,有新的链接请求到来时,新的链接请求将放置到链接队列中。当有链接释放给链接池时,链接池将新释放的链接分配给在队列中排队的链接请求。你能够调用close和dispose将链接归还给链接池。

4. 我应该如何容许链接池?

对于.NET应用程序而言,默认为容许链接池。(这意味着你能够没必要为这件事情作任何的事情)固然,若是你能够在SQLConnection对象的链接字符串中加进Pooling=true;确保你的应用程序容许链接池的使用。

5. 我应该如何禁止链接池?

ADO.NET默认为容许数据库链接池,若是你但愿禁止链接池,可使用以下的方式:

1) 使用SQLConnection对象时,往链接字符串加入以下内容:Pooling=False;

2) 使用OLEDBConnection对象时,往链接字符串加入以下内容:OLE DB Services=-4;

经过上面的两篇文章但愿你们能够明白什么是数据库链接池,何时适用,何时不适用。关于性能测试,我作了一个小例子,你们能够看看:

第一次运行:

屡次运行后:

测试按钮的代码以下:

string connStringUsePool = "server=.;database=pubs;uid=sa;pwd=123456;pooling=false";
            private void button1_Click(object sender, EventArgs e)  
            {  
                int count = 50;  
                DateTime start = DateTime.Now;  
                for (int i = 0; i < count; i++) 
                {  
                    using (SqlConnection conn = new SqlConnection(connStringUsePool)) 
                    { 
                        conn.Open();  
                        conn.Close();  
                    }  
                } 
                DateTime end = DateTime.Now;
                TimeSpan ts = end - start;  
                label1.Text = "使用链接池"+ts.Milliseconds.ToString(); 
                start = DateTime.Now; 
                for (int i = 0; i < count; i++)  
                { 
                    using (SqlConnection conn = new SqlConnection(connStringUnUsePool)) 
                    {  
                        conn.Open(); 
                        conn.Close(); 
                    } 
                }  
                end = DateTime.Now;  
                ts = end - start; 
                label2.Text = "不使用链接池" + ts.Milliseconds.ToString(); 
            }

转载:http://developer.51cto.com/art/200906/131898.htm

相关文章
相关标签/搜索