互联网解决方案咨询

梦想有多大路就会有多远:作一颗IT量子
  首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

数据库开发-数据库使用连接池

Posted on 2008-04-17 19:57  互联网粒子  阅读(1944)  评论(9编辑  收藏  举报
使用连接池
看看我们的ado.net的sqlconnection string的参数吧
<add name="SNETConnectionString" connectionString="Data Source=192.168.1.10;Initial Catalog=pandaDB;Persist Security Info=True;User ID=sa;Password=1234;MultipleActiveResultSets=true;Max Pool Size = 5;Min Pool Size = 3" providerName="System.Data.SqlClient "/>
其中我们设置了最大池数和最小池数,如何来看windows app 和web appp的区别呢
我们可以建一个web application或windows app,启用app后,你在sql分析器用sp_who2可以看到连接上来的客户端,很明显如果是web application或windows app每启动一个客户端就有n个connection上来,远远超过了Max Pool Size = 5,那就意味着app呢是每个Client就有一个连接池。
我们再来看网站,当你在开发网站,配置在IIS上时,其实是IIS与 DATABASE来交互,用同上的CONNECTION STRING看到,连接上来的Connection永远不会大于5,也就是说IIS与DATABASE间只存在一个连接池,不管有多个少个用户的请求,他是IIS APP对DATABASE APP。

具体可以参考下面的资料说明

连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等等。

实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使打开的连接成本最低,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 被卸载并且进程结束之前,连接池不会被破坏。非活动或空池的维护只需要最少的系统开销。

Note注意

如果发生致命错误(例如故障转移或注册表中的别名更改),池将自动清除。

添加连接

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

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

连接池进程通过在连接释放回池中时重新分配连接,来满足这些连接请求。如果已达到最大池大小且不存在可用的连接,则该请求将会排队。然后,池进程尝试重新建立任何连接,直到到达超时时间(默认值为 15 秒)。如果池进程在连接超时之前无法满足请求,将引发异常。

Caution note警告

我 们建议您在使用完连接时一定要关闭连接,以便连接可以返回池。要关闭连接,可以使用 Connection 对象的 Close 或 Dispose 方法,也可以通过在 C# 的 using 语句中或在 Visual Basic 的 Using 语句中打开所有连接。不是显式关闭的连接可能不会添加或返回到池中。例如,如果连接已超出范围但没有显式关闭,则仅当达到最大池大小而该连接仍然有效时, 该连接才会返回到连接池中。有关更多信息,请参见 Visual Basic 的using 语句(C# 参考)如何:释放系统资源

Note注意

不 要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。有关更多信息,请参见垃圾回收

移除连接

连接池进程定期扫描连接池,查找没有通过 Close 或 Dispose 关闭的未用连接,并重新建立找到的连接。如果应用程序没有显式关闭或断开其连接,连接池进程可能需要很长时间才能重新建立连接,所以,最好确保在连接中显式调用 Close 和 Dispose。

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

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

清除池

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

事务支持

连接是根据事务上下文来从池中取出并进行分配的。除非在连接字符串中指定了 Enlist=false,否则,连接池将确保连接在 Current 上下文中登记。如果连接使用登记的 System.Transactions 事务关闭并返回池中,连接将保留在池中,以便使用相同 System.Transactions 事务对该连接池的下一次请求将返回相同的连接。如果该事务没有可用连接,在该连接打开时,将自动注册该连接。

当连接关闭时,它将被释放回池中,并根据其事务上下文放入相应的子部分。因此,即使分布式事务仍然挂起,仍可以关闭该连接而不会生成错误。这样,您就可以在随后提交或中止分布式事务。

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

SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对,可以用于调整连接池逻辑的行为。有关更多信息,请参见 ConnectionString

池碎片

池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会创建大量在进程退出后才会释放的池。这样,将打开大量的连接,占用许多内存,从而影响性能。

因为集成安全性产生的池碎片

连 接根据连接字符串以及用户标识来建立池连接。因此,如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录,每个用户将获得一个池。尽管这样可以提高单个用户的后续数据库请求的性能,但是该用户无法利用其他用户建立的连接。这样还使 每个用户至少产生一个与数据库服务器的连接。这对特定 Web 应用程序结构会产生副作用,因为开发人员需要衡量安全性和审计要求。

因为许多数据库产生的池碎片

许 多 Internet 服务提供商在一台服务器上托管多个网站。他们可能使用单个数据库确认窗体身份验证登录,然后为该用户或用户组打开与特定数据库的连接。与身份验证数据库的 连接将建立池连接,供每个用户使用。但是,每个数据库的连接存在一个独立的池,因此增加了与服务器的连接数。

这也会对应用程序设计产生副 作用。但是,可以通过一个相对简单的方式避免此副作用,而又不会影响连接 SQL Server 时的安全性。不是为每个用户或组连接独立的数据库,而是连接到服务器上的相同数据库,然后执行 Transact-SQL USE 语句来切换为所需的数据库。以下代码段演示入如何创建与 master 数据库的初始连接,然后切换到 databaseName 字符串变量中指定的所需数据库。

Visual Basic
' Assumes that command is a valid SqlCommand object.
Using connection As New SqlConnection( _
"Server=MSSQL1;uid=xxx;pwd=xxx;database=master")
connection.Open()
command.ExecuteNonQuery("USE " & databaseName)
End Using
// Assumes that command is a SqlCommand object.
using (SqlConnection connection = new SqlConnection(
"Server=MSSQL1;uid=xxx;pwd=xxx;database=master"))
{
connection.Open();
command.ExecuteNonQuery("USE " + databaseName);
}

应用程序角色和连接池

通过调用 sp_setapprole 系统存储过程激活了 SQL Server 应用程序角色之后,该连接的安全上下文无法重置。但是,如果启用了池,连接将返回池,在重复使用池连接时会出错。

如果使用的是 SQL Server 应用程序角色,我们建议您在连接字符串中为应用程序禁用连接池。有关更多信息,请参见知识库文章