ADO.NET 连接池一览






4.77/5 (114投票s)
连接池可以通过为连续的请求使用池中的活动连接来提高任何应用程序的性能,而不是每次都创建一个新连接。同时,作为应用程序最佳判断者的开发人员可以配置连接池。
目录
- ADO.NET 连接池一览
- 连接池创建
- 连接池删除/清空连接池
- 通过连接字符串控制连接池
- 包含与池相关的关键字的示例连接字符串
- 查看 ADO.NET 创建的连接池中的连接的简单方法
- 连接池的常见问题/异常/错误
- 值得思考的点
- 关于连接池的其他有用阅读/参考
- 总结
ADO.NET 连接池一览
与数据库服务器建立连接是一个繁琐且资源消耗巨大的过程。如果任何应用程序需要对任何数据库服务器执行任何查询,我们都需要先与服务器建立连接,然后对该数据库服务器执行查询。
不确定您是否曾有过这种感觉:当您编写任何存储过程或查询时,该查询返回结果的响应时间比从任何客户端应用程序执行相同查询的响应时间要快。我相信,造成这种行为的原因之一是数据库服务器到客户端应用程序获取所需结果所涉及的开销;而其中一项开销就是建立 ADO 之间的连接。
Web 应用程序频繁建立数据库连接,并在完成后立即关闭它们。还注意到我们大多数人是如何编写数据库驱动的客户端应用程序的。通常,我们会有一个特定于应用程序的配置文件,并将连接字符串等静态信息保存在其中。这意味着,在大多数情况下,我们需要为大小事务连接到同一个数据库服务器、同一个数据库,并使用相同的用户名和密码。
ADO.NET 与 IIS 结合使用一种称为连接池的技术,这对于具有此类设计的应用程序非常有帮助。它的作用是,在第一次请求数据库时,它会响应数据库调用。一旦完成,当客户端应用程序请求关闭连接时,ADO.NET 不会销毁整个连接,而是创建一个连接池,将释放的连接对象放入池中并保留其引用。下次当请求执行任何查询/存储过程时,它会绕过建立连接的繁琐过程,直接从连接池中提取连接并将其用于此次数据库调用。这样,它就可以相对更快地返回结果。
让我们更详细地看看连接池的创建机制。
连接池创建
连接池与连接字符串相辅相成。每个连接池都与一个不同的连接字符串相关联,并且该字符串特定于应用程序。反过来,这意味着 - 每个不同的进程、应用程序域和连接字符串都会维护一个单独的连接池。
当通过 ADO.NET 做出任何数据库请求时,ADO.NET 会在同一个应用程序域和进程中搜索与连接字符串完全匹配的池。如果找不到这样的池,ADO.NET 会为其创建一个新的池;但是,如果找到了,它会尝试从该池中获取可用的连接。如果在池中找不到任何可用的空闲连接,则会创建一个新连接并将其添加到池中。这样,新连接会不断添加到池中,直到达到 **最大池大小**,之后当 ADO.NET 收到更多连接请求时,它会等待 **连接超时** 时间,然后报错。
现在,下一个问题是 - 如何将任何连接释放到池中以供将来使用?一旦连接完成服务并被关闭/释放,连接就会进入连接池并变得可用。有时,连接不会显式关闭/释放,这些连接不会立即进入池。我们可以通过使用连接对象的 `Close()` 或 `Dispose()` 方法,或者在 C# 中使用 `using` 语句实例化连接对象来显式关闭连接。强烈建议在连接完成其用途后关闭或释放它(不要等待 GC 或连接池来为您完成)。
连接池删除/清空连接池
连接池在关联的应用程序域卸载时即被移除。一旦应用程序域卸载,连接池中的所有连接都将失效并被移除。例如,如果您有一个 ASP.NET 应用程序,连接池会在您第一次访问数据库时创建,并在我们执行 `iisreset` 时销毁。稍后我们将通过示例进行演示。请注意,连接池与 IIS Web 服务器有关,与开发环境无关,因此不要期望关闭 Visual Studio .NET 开发环境可以自动清除连接池。
ADO.NET 2.0 引入了两个新方法来清除池:`ClearAllPools` 和 `ClearPool`。`ClearAllPools` 清除给定提供程序的连接池,而 `ClearPool` 清除与特定连接关联的连接池。如果在调用时有正在使用的连接,它们会被适当地标记。当它们被关闭时,它们将被丢弃而不是返回到池中。
有关如何确定池状态的详细信息,请参阅“查看 ADO.NET 创建的连接池中的连接的简单方法”部分。
通过连接字符串控制连接池
连接字符串在连接池中起着至关重要的作用。ADO.NET 与数据库服务器之间的握手仅基于此连接字符串。下面是包含重要的连接池特定连接字符串关键字及其说明的表格。
名称 | 默认值 | 描述 |
连接生存期 | 0 | 当连接返回到池时,会将其创建时间与当前时间进行比较,如果时间跨度(以秒为单位)超过 **连接生存期** 指定的值,则会销毁该连接。零 (0) 的值会导致池中的连接具有最大连接超时。 |
连接超时 | 15 | 从池中获取空闲连接的最大等待时间(以秒为单位) |
注册 | 'true' | 当设置为 `true` 时,池化程序会自动将连接注册到创建线程的当前事务上下文中。可识别的值为 `true`、`false`、`yes` 和 `no`。将 `Enlist = "false"` 设置为确保连接不是上下文特定的。 |
最大池大小 | 100 | 池中允许的最大连接数。 |
最小池大小 | 0 | 池中允许的最小连接数。 |
池化 | 'true' | 当设置为 `true` 时,`SQLConnection` 对象将从相应的池中获取,或者在需要时创建并添加到相应的池中。可识别的值为 `true`、`false`、`yes` 和 `no`。 |
池大小增量 | 5 | 控制当所有连接都被使用时建立的连接数。 |
池大小减量 | 1 | 控制当建立的连接过多而未使用时关闭的连接数。 |
*部分表格内容摘自 Microsoft MSDN 库供参考。
除了上面提到的关键字,还有一点很重要。**如果您使用集成身份验证,则为访问客户端系统的每个用户创建连接池;而当您在连接字符串中使用用户 ID 和密码时,将为应用程序维护一个单一连接池。** 在后一种情况下,每个用户都可以使用其他用户创建和释放到池中的连接。因此,建议使用用户 ID 和密码以获得更好的最终用户性能体验。
包含与池相关的关键字的示例连接字符串
包含与池相关的关键字的连接字符串大致如下
initial catalog=Northwind; Data Source=localhost; Connection Timeout=30;
User Id=MYUSER; Password=PASSWORD; Min Pool Size=20; Max Pool Size=200;
Incr Pool Size=10; Decr Pool Size=5;
查看 ADO.NET 创建的连接池中的连接的简单方法
我们可以通过在客户端应用程序关闭后确定数据库中的活动连接来监视池中的连接。这是数据库特定的内容,因此要查看数据库服务器中的活动连接,我们必须使用数据库特定的查询。**前提是连接池完全有效且池中的任何连接都没有损坏。**
对于 Microsoft SQL Server:打开查询分析器并执行查询:`EXEC SP_WHO`。
对于 Oracle:打开 SQL Plus 或任何其他编辑器,如 PL/SQL Developer 或 TOAD,并执行以下查询 -- `SELECT * FROM V$SESSION WHERE PROGRAM IS NOT NULL`。
好了,我们用 SQL Server 2000 来做。
- 创建一个示例 ASP.NET Web 应用程序
- 打开一个查询分析器实例并运行 `EXEC SP_WHO` 查询。记下 `loginname` 列,并查找 `MACHINENAME\ASPNET`。如果您还没有运行任何其他 ASP.NET 应用程序,您将不会看到 `loginname` 为 `MACHINENAME\ASPNET` 的行。
- 在默认启动页的 Page_Load 事件中,添加一个进行数据库调用的方法。假设您的连接字符串是 `“initial catalog=Northwind; Min Pool Size=20;Max Pool Size=500; data source=localhost; Connection Timeout=30; Integrated security=sspi”`。
- 运行您的 ASP.NET 应用程序
- 现在重复步骤 2,观察结果中正好有 20 个连接(最小池大小)。请注意,您只进行了一次数据库调用。
- 关闭您的 Web 应用程序的网页并重复步骤 2。观察即使您关闭了网页实例,连接仍然存在。
- 现在重置 IIS。您可以通过在“运行”命令中执行 `iisreset` 命令来完成。
- 现在重复步骤 2,并观察所有 20 个连接都已消失。这是因为您的应用程序域已随着 IIS 重置而被卸载。
连接池的常见问题/异常/错误
-
您的 .NET 客户端应用程序中会收到一条异常,消息为:“**超时已过期。在从池中获取连接之前,超时时间已到。这可能是因为所有池中的连接都已在使用中并且已达到最大池大小。**”
当您尝试使用的连接数超过最大池大小时,会发生这种情况。默认情况下,最大池大小为 100。如果我们尝试获取的连接数超过最大池大小,ADO.NET 将等待 **连接超时** 时间从池中获取连接。即使在那之后连接仍然不可用,我们也会收到上述异常。
解决方案
- 我们应该做的第一件事是——确保所有打开的连接都已显式关闭。有时会发生这种情况:我们打开连接,执行所需的数据库操作,但没有显式关闭连接。在内部,它不能被用作池中可用的有效连接。应用程序将不得不等待 GC 来回收它,在此之前它不会被标记为池中可用。在这种情况下,即使您没有同时使用最大池大小的连接数,您也可能会收到此错误。**这是此问题的最可能原因。**
- 将最大池大小值增加到一个足够大的值。您可以通过在连接字符串中包含 `"Max Pool Size = N;"` 来实现,其中 `N` 是新的最大池大小。
- 将池设置 `Off`。嗯,这确实不是一个好主意,因为连接池对性能有积极影响,但它肯定比收到任何此类异常要好。
-
您的 ASP.NET 应用程序在使用 Microsoft SQL Server 时会收到一条异常,消息为:“**发送请求到服务器时发生传输级错误。(提供程序:共享内存提供程序,错误:0 - 共享内存提供程序:)**”
当 Microsoft SQL Server 2000 遇到某些问题并需要刷新所有连接时,ADO.NET 仍然期望从池中获取连接。基本上,这是因为连接池已损坏。实际上发生的是,ADO.NET 认为数据库服务器上存在有效连接,但实际上,由于数据库服务器已重新启动,它已丢失所有连接。
解决方案
- 如果您正在使用 ODP.NET v 9.2.0.4 或更高版本通过 .NET 和 Oracle 进行开发,您可以尝试在连接字符串中添加 `"Validate Connection=true"`。嗯,在几个地方,我注意到有人说使用 `"validcon=true"` 对 ODP.NET 的早期版本有效。看看哪个适合您。对于 ODP.NET v 9.2.0.4,`"validcon=true"` 会出错,而 `"Validate Connection=true"` 则正常工作。
- 如果您正在使用 .NET 2.0 和 Microsoft SQL Server,您可以使用 `static`(在 Visual Basic .NET 中为共享)方法 `SqlConnection.ClearPool` 来清除特定连接池,或者使用 `SqlConnection.ClearPools` 方法清除应用程序域中的所有连接池。SqlClient 和 OracleClient 都实现了此功能。
- 如果您正在使用 .NET 1.1 和 Microsoft SQL Server
- 在连接字符串中,在运行时,附加一个空格并尝试重新建立连接。这样,将会创建一个新的连接池,并由您的应用程序使用。与此同时,如果旧池未被使用,它将被移除。
- 进行异常处理,并且一旦您收到此错误,就在循环中反复尝试重新连接。随着时间的推移,ADO.NET 和数据库服务器将自动同步。
嗯,我对这两种方法都不完全满意,但坦白说,到目前为止我还没有找到更好的可行解决方案。
-
连接泄漏
当我们不关闭/释放连接时,GC 会在其自己的时间收集它们,从池的角度来看,这些连接被视为已泄漏。有一种奇怪的可能性是,我们达到了最大池大小,而在那个时刻,没有实际使用所有连接,其中一些连接已经泄漏并等待 GC 来处理它们。即使我们没有同时使用最大池大小的连接数,这实际上也会导致上述异常。
解决方案
- 确保在使用完毕后关闭/释放连接。
关于连接池的其他有用阅读/参考
总结
简而言之,连接池可以通过为连续的请求使用池中的活动连接来提高任何应用程序的性能,而不是每次都创建一个新连接。默认情况下,ADO.NET 会启用并使用连接池,因为它具有积极的影响。同时,作为应用程序最佳判断者的开发人员可以通过简单地使用连接字符串中的强大关键字来配置连接池功能,甚至根据应用程序的需要将其关闭。
请花些时间评价和提供关于本文的反馈。您的几分钟时间可以帮助提高本文的质量。
如果您有兴趣,请点击 此处 查看我发布的所有文章。