6

我必须使用另一个开发人员制作的项目。带有 Visual-Basic 代码的项目 Win-Form,MS-Access 作为 db 和一些 OleDbConnections。有一个错误:有时应用程序无法打开 OleDbConnection,因为在 db 上已达到最大连接数。我知道使用连接的最佳方法是:

Using cn As New OleDbConnction(s)
  ...
  cn.Close()
End Using

但是在项目中,有许多类可以与数据库一起使用,并且在这些类中的许多类中都有具有“朋友”可见性的 OleDbConnections,它们在不同的时间打开和关闭。出于这个原因,不可能将所有 OleDbConnections 放在 Using 构造中,而且很难找到“忘记”关闭其中一个 OleDbConnection 的操作。

一种可能的解决方案是仅使用一个唯一的公共 OleDbConnection,并在打开它之前检查它是否尚未打开。但有人告诉我这是一个非常糟糕的做法。我想他告诉我这个关于表演的事,但我不知道确切的。你能告诉我为什么一个独特的公共 OleDbConnection 如此被弃用吗?对我来说,你有一个“简单”的解决方案来解决我的问题吗?谢谢你,皮莱吉

4

2 回答 2

6

从您的描述中,我看到了一些可能导致您出现问题的问题:

  • 嵌套连接:
    您在彼此之间打开多个连接
  • 打开/释放连接太快:
    正如 David-W-Fenton 提到的,通过访问,每次打开/关闭单个连接时,都会创建/删除锁定文件。此操作非常慢,如果您在应用程序中快速打开/关闭数据库(执行大量原子查询),您可能会遇到此问题。

调查和解决问题的几种可能方法:

跟踪所有打开/关闭调用
添加一些调试跟踪,显示每次打开和关闭连接。
它将允许您检测嵌套连接以及连接池被浪费的位置。

强制连接轮询 一个简单的“修复”可能是在连接字符串中明确设置连接池。它应该是默认行为,所以也许它不会做任何事情来解决你的问题,但它是如此简单,没有理由不尝试它:

OLE DB Services=-1

使用连接管理器类为您创建/释放连接。
用您自己的代码替换所有显式创建的新 OleDbConnection 和关闭操作。这将允许您始终在整个应用程序中重用单个现有连接,并允许您通过将行为集中在一个地方来快速调整整个应用程序。

那么为什么通常不推荐使用单个连接呢?

  • 通常,您不应该在整个应用程序中保持连接打开,因为它们会强制数据库服务器为您保留可用资源,并且会减少可以连接的客户端数量(始终可用的连接数量是有限的)。
    但是对于 Access - 一个没有服务器部分的基于文件的数据库 - 保持单个连接打开实际上是更可取的,因为与打开新连接(创建锁定文件)相关的延迟。由于 Access 不适合与大量并发用户一起使用,因此保持连接打开的资源成本不足以成为问题。
    从简单的测试中可以看出,保持连接始终打开可以使后续连接的打开速度提高约 10 倍!

  • OleDb 驱动程序为您执行连接池,因此它能够在连接被释放时重新使用它们。

  • 通过保持您的连接和数据库操作较小且包含在内,您在使用线程时不太可能遇到并发问题。如果您使用同一个数据库管道执行多个操作,保持全局连接可能会成为一个问题。

于 2011-06-16T04:28:55.903 回答
2

只需添加一些对我有用多年的信息(这有点类似于David-W-Fenton 的建议

首先,OleDbConnectionMicrosoft Access(MDB、JET)没有使用连接池。正如微软在 KB191572 中所说

使用 Jet OLE DB 提供程序和 ODBC 驱动程序的连接不会被池化,因为这些提供程序和驱动程序不支持池化。

关于连接池,还有Ivan Mitev 的这篇博文指出:

那么这是什么意思?很明显,主动打开的连接的存在使得多个连接关闭和打开的测试完成得更快(2-3次)。对我来说唯一可能的解释是每次没有活动连接时都会释放连接池。我必须进行进一步调查并阅读 Microsoft Data Access Components 中的 Pooling 之类的内容。或者可能只是为了保持池的活动而保持一个打开的连接。这将是丑陋的,但它仍然是一个足够好的解决方法!如果有人有更好的想法,请分享。

微软在 MSDN 中的注释

ADO Connection 对象隐式使用 IDataInitialize。但是,这意味着您的应用程序需要始终为每个唯一用户保留至少一个实例化的 Connection 对象实例。否则,当该字符串的最后一个 Connection 对象关闭时,池将被销毁。

基于所有这些和我自己的测试,即使使用 Microsoft Access 数据库,的“模拟”连接池的解决方案也大致遵循以下步骤:

  1. OleDbConnection在应用程序生命周期中尽早打开一个到 Access 数据库。
  2. 执行您的正常 SQL 查询,OleDbConnection尽可能早地处理 s,就像推荐的那样。
  3. OleDbConnection在应用程序生命周期中尽可能晚地处理始终打开的那个。

这极大地加快了我的应用程序(主要是 WinForms)的速度。

请注意,这也适用于似乎也不支持连接池的 Sqlite。

于 2014-08-08T06:10:43.590 回答