做者:可米小子
出处:http://liuhaorain.cnblogs.com html
在上篇文章《你必须知道的ADO.NET(四) 品味Connection对象》中,我已经强调过,创建一个数据库链接是一件很是耗时(消耗时间)耗力(消耗资源)的事情。之因此会这样,是由于链接到数据库服务器须要经历几个漫长的过程:创建物理通道(例如套接字或命名管道),与服务器进行初次握手,分析链接字符串信息,由服务器对链接进行身份验证,运行检查以便在当前事务中登记等等。咱们先无论为何会有这样的机制,存在老是有它的道理。既然新建一条链接如此痛苦,那么为何不重复利用已有的链接呢?数据库
实际上,ADO.NET已经为咱们提供了名为链接池的优化方法。链接池就是这样一个容器:它存放了必定数量的与数据库服务器的物理链接。所以,当咱们须要链接数据库服务器的时候,只需去池(容器)中取出一条空闲的链接,而不是新建一条链接。这样的话,咱们就能够大大减小链接数据库的开销,从而提升了应用程序的性能。windows
PS:原本作了2张图片来描述链接池的,无奈公司装有监控软件,不能上传,因此只能等下次有时间上传了。安全
须要说明的是,链接池是具备类别区分的。也就是说,同一个时刻同一应用程序域能够有多个不一样类型的链接池。那么,链接池是如何标识区分的?细致的讲,是由进程、应用程序域、链接字符串以及windows标识(在使用集成的安全性时)共同组成签名来标识区分的。但对于同一应用程序域来讲,通常只由链接字符串来标识区分。当打开一条链接时,若是该条链接的类型签名与现有的链接池类型不匹配,则建立一个新的链接池。反之,则不建立新的链接池。服务器
一个典型的建立链接的实例:性能
//建立链接对象1
using (SqlConnection conn1 =
new SqlConnection( "DataSource=(local);Integrated Security=SSPI;Initial Catalog=Northwind"))
{
conn1.Open();
}
//建立链接对象2
using (SqlConnection conn2 =
new SqlConnection( "DataSource=(local);Integrated Security=SSPI;Initial Catalog=pubs"))
{
conn2.Open();
}
//建立链接对象3
using (SqlConnection conn3 =
new SqlConnection( "DataSource=(local);Integrated Security=SSPI;Initial Catalog=Northwind"))
{
conn3.Open();
}
上面实例中,我建立了三个SqlConnection对象,可是管理时只须要两个链接池。细心的朋友,可能早已发现conn1与conn3的链接字符串相同,因此能够共享一个链接池,而conn2与conn1与conn3不一样,因此须要建立新的链接池。优化
当用户建立链接请求或者说调用Connection对象的Open时,链接池管理器首先须要根据链接请求的类型签名找到匹配类型的链接池,而后尽力分配一条空闲链接。具体状况以下:ui
无效链接,即不能正确链接到数据库服务器的链接。对于链接池来讲,存储的与数据库服务器的链接的数量是有限的。所以,对于无效链接,若是如不及时移除,将会浪费链接池的空间。其实你不用担忧,链接池管理器已经很好的为咱们处理了这些问题。若是链接长时间空闲,或检测到与服务器的链接已断开,链接池管理器会将该链接从池中移除。spa
当咱们使用完一条链接时,应当及时关闭或释放链接,以便链接能够返回池中重复利用。咱们能够经过Connection对象的Close或Dispose方法,也能够经过C#的using语句来关闭链接。3d
链接池的行为能够经过链接字符串来控制,主要包括四个重要的属性:
仍是看一个实例来理解链接池的属性吧。代码以下:
SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
connStr.DataSource = @".\SQLEXPRESS";
connStr.InitialCatalog = "master";
connStr.IntegratedSecurity = true;
connStr.Pooling = true; //开启链接池
connStr.MinPoolSize = 0; //设置最小链接数为0
connStr.MaxPoolSize = 50; //设置最大链接数为50
connStr.ConnectTimeout = 10; //设置超时时间为10秒
using( SqlConnection conn = new SqlConnection(connStr.ConnectionString))
{
;//todo
}
当用户打开一个链接而没有正确或者及时的关闭时,常常会引起“链接泄露”问题。泄露的链接,会一直保持打开状态,直到调用Dispose方法,垃圾回收器(GC)才关闭和释放链接。与ADO不一样,ADO.NET须要手动的关闭使用完的链接。一个重要的误区是:当链接对象超出局部做用域范围时,就会关闭链接。实际上,当超出做用域时,释放的只是链接对象而非链接资源。好吧,仍是先看看一个实例吧。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace ConnectionPool
{
class Program
{
static void Main(string[] args)
{
SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
connStr.DataSource = @".\SQLEXPRESS";
connStr.InitialCatalog = "master";
connStr.IntegratedSecurity = true;
connStr.MaxPoolSize = 5;//设置最大链接池为5
connStr.ConnectTimeout = 1;//设置超时时间为1秒
SqlConnection conn = null;
for (int i = 1; i <= 100; ++i)
{
conn = new SqlConnection(connStr.ConnectionString);
try
{
conn.Open();
Console.WriteLine("Connection{0} is linked",i);
}
catch(Exception ex)
{
Console.WriteLine("\n异常信息:\n{0}",ex.Message);
break;
}
}
Console.Read();
}
}
}
为了使结果更明显,我特意将最大链接数设置为5,超时时间为1秒。运行后,很快获得如下结果。
从上面的结果咱们很明显的知道,链接出现了异常。咱们已经知道链接池的最大链接数为5,当建立第6条链接时,因为链接池中链接数量已经达到了最大数而且没有空闲的链接,所以须要等待链接直到超时。当超过超时时间时,就出现了上述的链接异常。所以,我必须再次强调,使用完的链接应当尽快的正确的关闭和释放。
第一步:打开MSSMS管理器,单击“活动监视器”图标。
第二步:在打开活动监视器视图中,单击“进程”选项卡。
第三步:运行 #4 链接池异常与处理方法 中的例子,则能够看到打开的5条链接,以下图所示。
一样,经过执行系统存储过程sp_who,咱们也能够监视链接状态。
exec sp_who
可获得如下结果:
用好链接池将会大大提升应用程序的性能。相反,若是使用不当的话,则百害而无一益。通常来讲,应当遵循如下原则:
提示:池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会建立大量在进程退出后才会释放的池。 这样,将打开大量的链接,占用许多内存,从而致使性能下降。