q接到数据库服务器通常由几个需要很长时间的步骤l成。必d立物理通道Q例如套接字或命名管道)(j)Q必M服务器进行初ơ握手,必须分析q接字符串信息,必须由服务器对连接进行n份验证,必须q行(g)查以便在当前事务中登讎ͼ{等?
实际上,大多数应用程序仅使用一个或几个不同的连接配|。这意味着在执行应用程序期_(d)许多相同的连接将反复地打开和关闭。ؓ(f)了打开的连接成本最低,ADO.NET 使用UCؓ(f)q接?/em>的优化方法?/p>
q接池减新q接需要打开的次数?em>池进E?/em>保持物理q接的所有权。通过为每个给定的q接配置保留一l活动连接来理q接。只要用户在q接上调?OpenQ池q程׃(x)(g)查池中是否有可用的连接。如果某个池q接可用Q会(x)该q接q回l调用者,而不是打开新连接。应用程序在该连接上调用 Close Ӟ池进E会(x)连接返回到zdq接池集中,而不是真正关闭连接。连接返回到池中之后Q即可在下一?Open 调用中重复用?/p>
只有配置相同的连接可以徏立池q接。ADO.NET 同时保留多个池,每个配置一个池。连接由q接字符串以?Windows 标识Q在使用集成的安全性时Q分为多个池?/p>
池连接可以大大提高应用程序的性能和可~放性。默认情况下QADO.NET 中启用连接池。除非显式禁用,否则Q连接在应用E序中打开和关闭时Q池q程对q接q行优化。还可以提供几个q接字符串修饰符来控制连接池的行为。有x多信息,请参见本主题后面?#8220;使用q接字符串关键字控制q接?#8221;?/p>
在初ơ打开q接Ӟ根据完全匹配算法创接池Q该法池与连接中的连接字W串兌。每个连接池与不同的q接字符串关联。打开新连接时Q如果连接字W串q与现有池完全匚wQ将创徏一个新池。按q程、按应用E序域、按q接字符串以?qing)(在用集成的安全性时Q按 Windows 标识来徏立池q接?/p>
在以?C# CZ中创Z三个新的 SqlConnection 对象Q但是管理时只需要两个连接池。注意,Ҏ(gu)?Initial Catalog 分配的|W一个和W二个连接字W串有所不同?/p>
如果 MinPoolSize 在连接字W串中未指定或指定ؓ(f)Ӟ池中的连接将在一D|间不zd后关闭。但是,如果指定?MinPoolSize 大于Ӟ?AppDomain 被卸载ƈ且进E结束之前,q接池不?x)被破坏。非zd或空池的l护只需要最的pȝ开销?/p>
如果发生致命错误Q例如故障{UL注册表中的别名更改)(j)Q池自动清除?/p>
q接池是为每个唯一的连接字W串创徏的。当创徏一个池后,创建多个连接对象ƈ其d到该池中Q以满最池大小的要求。连接根据需要添加到池中Q但是不能超q指定的最大池大小Q默认gؓ(f) 100Q。连接在关闭或断开旉攑֛池中? 在请?SqlConnection 对象Ӟ如果存在可用的连接,从池中获取该对象。连接要可用Q必L使用Q具有匹配的事务上下文或未与M事务上下文关联,q且h与服务器的有效链接?/p>
q接池进E通过在连接释攑֛池中旉新分配连接,来满些连接请求。如果已辑ֈ最大池大小且不存在可用的连接,则该h会(x)排队。然后,池进E尝试重新徏立Q何连接,直到到达时旉Q默认gؓ(f) 15 U)(j)。如果池q程在连接超时之前无法满求,引发异常? 我们(zhn)在使用完连接时一定要关闭q接Q以便连接可以返回池。要关闭q接Q可以?Connection 对象?Close ?Dispose Ҏ(gu)Q也可以通过?C# ?using 语句中或?Visual Basic ?Using 语句中打开所有连接。不是显式关闭的q接可能不会(x)d或返回到池中。例如,如果q接已超围但没有昑ּ关闭Q则仅当辑ֈ最大池大小而该q接仍然有效Ӟ该连接才?x)返回到q接池中。有x多信息,请参?Visual Basic ?a id=ctl00_rs1_mainContentContainer_ctl03 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl03',this);" tabIndex=0 >using 语句QC# 参考)(j)?a id=ctl00_rs1_mainContentContainer_ctl04 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl04',this);" tabIndex=0 >如何Q释攄l资?/font>?/p>
不要在类?Finalize Ҏ(gu)中对 Connection、DataReader 或Q何其他托对象调?Close ?Dispose。在l结器中Q仅释放cȝ接拥有的非托资源。如果类不拥有Q何非托管资源Q则不要在类定义中包?Finalize Ҏ(gu)。有x多信息,请参?a id=ctl00_rs1_mainContentContainer_ctl05 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl05',this);" tabIndex=0 >垃圾回收?/p>
q接池进E定期扫描连接池Q查找没有通过 Close ?Dispose 关闭的未用连接,q新徏立找到的q接。如果应用程序没有显式关闭或断开其连接,q接池进E可能需要很长时间才能重新徏立连接,所以,最好确保在q接中显式调?Close ?Dispose?/p>
如果q接长时间空Ԍ或池q程(g)到与服务器的连接已断开Q连接池q程?x)将该连接从池中U除。注意,只有在尝试与服务器进行通信之后才能(g)到断开的连接。如果发现某q接不再q接到服务器Q则?x)将其标Cؓ(f)无效。无效连接只有在关闭或重新徏立后Q才?x)从q接池中U除?/p>
如果存在与已消失的服务器的连接,那么即ɘq接池管理程序未(g)到已断开的连接ƈ其标记为无效,仍有可能此q接从池中取出。这U情冉|因ؓ(f)(g)查连接是否仍有效的系l开销造成与服务器的另一ơ往q,从而抵消了池进E的优势。发生此情况Ӟ初次试使用该连接将(g)连接是否曾断开Qƈ引发异常?/p>
ADO.NET 2.0 引入了两U新的方法来清除池:(x)ClearAllPools ?ClearPool。ClearAllPools 清除l定提供E序的连接池QClearPool 清除与特定连接关联的q接池。如果在调用时连接正在用,进行相应的标记。连接关闭时Q将被丢弃,而不是返回池中?/p>
q接是根据事务上下文来从池中取出q进行分配的。除非在q接字符串中指定?Enlist=falseQ否则,q接池将保q接?Current 上下文中登记。如果连接用登记的 System.Transactions 事务关闭q返回池中,q接保留在池中Q以便用相?System.Transactions 事务对该q接池的下一ơ请求将q回相同的连接。如果该事务没有可用q接Q在该连接打开Ӟ自动注册该q接?/p>
当连接关闭时Q它?yu)被释放回池中,q根据其事务上下文放入相应的子部分。因此,即分布式事务仍然挂P仍可以关闭该q接而不?x)生成错误。这P(zhn)就可以在随后提交或中止分布式事务?/p>
SqlConnection 对象?ConnectionString 属性支持连接字W串?值对Q可以用于调整连接池逻辑的行为。有x多信息,请参?ConnectionString?/p>
池碎片是许多 Web 应用E序中的一个常见问题,应用E序可能?x)创建大量在q程退出后才会(x)释放的池。这P打开大量的连接,占用许多内存Q从而媄(jing)响性能?/p>
q接Ҏ(gu)q接字符串以?qing)用h识来建立池连接。因此,如果使用|站上的基本w䆾验证?Windows w䆾验证以及(qing)集成的安全登录,每个用户获得一个池。尽这样可以提高单个用L(fng)后箋数据库请求的性能Q但是该用户无法利用其他用户建立的连接。这栯使每个用戯生一个与数据库服务器的连接。这对特?Web 应用E序l构?x)生副作用Q因为开发h员需要衡量安全性和审计要求?/p>
许多 Internet 服务提供商在一台服务器上托多个网站。他们可能用单个数据库认H体w䆾验证dQ然后ؓ(f)该用h用户l打开与特定数据库的连接。与w䆾验证数据库的q接徏立池q接Q供每个用户使用。但是,每个数据库的q接存在一个独立的池,因此增加了与服务器的q接数?/p>
q也?x)对应用E序设计产生副作用。但是,可以通过一个相对简单的方式避免此副作用Q而又不会(x)影响q接 SQL Server 时的安全性。不是ؓ(f)每个用户或组q接独立的数据库Q而是q接到服务器上的相同数据库,然后执行 Transact-SQL USE 语句来切换ؓ(f)所需的数据库。以下代码段演示入如何创Z master 数据库的初始q接Q然后切换到 databaseName 字符串变量中指定的所需数据库?/p>
通过调用 sp_setapprole pȝ存储q程ȀzM SQL Server 应用E序角色之后Q该q接的安全上下文无法重置。但是,如果启用了池Q连接将q回池,在重复用池q接时会(x)出错?/p>
如果使用的是 SQL Server 应用E序角色Q我们徏议?zhn)在连接字W串中ؓ(f)应用E序用q接池。有x多信息,请参见知识库文章“SQL application role errors with OLE DB resource pooling”?/p>
池的创徏和分?/h1>
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.
}
注意
dq接
警告
注意
U除q接
清除?/h1>
事务支持
使用q接字符串关键字控制q接?/h1>
池碎?/h1>
因ؓ(f)集成安全性生的池碎?/h3>
因ؓ(f)许多数据库生的池碎?/h3>
// 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);
}应用E序角色和连接池