为啥不推荐使用一个 Public OleDbConnection?解决该错误的替代方法:打开的连接过多

Posted

技术标签:

【中文标题】为啥不推荐使用一个 Public OleDbConnection?解决该错误的替代方法:打开的连接过多【英文标题】:Why one Public OleDbConnection is deprecated? Alternative to solve the bug: too many connections opened为什么不推荐使用一个 Public OleDbConnection?解决该错误的替代方法:打开的连接过多 【发布时间】:2011-06-15 17:44:51 【问题描述】:

我必须使用其他开发人员制作的项目。带有 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 如此被弃用吗? 对我来说,你有一个“简单”的解决方案来解决我的问题吗? 谢谢, 皮莱吉

【问题讨论】:

对 Jet/ACE 数据库使用单个持久连接是正确的方法。它是一个文件,而不是连接另一端的服务器进程,打开连接(创建 LDB 文件)会产生大量开销。换句话说,打开/关闭多个连接没有实际好处,使用单个持久连接也没有真正的缺点。您所遵循的建议适用于基于服务器的数据库引擎,但不适用于 Jet/ACE 等基于文件的数据库。 同意。在您的情况下,将单个连接对象声明为 Public 是一个好主意。 【参考方案1】:

根据您的描述,我发现有几个可能导致您出现问题的问题:

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

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

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

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

OLE DB Services=-1

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

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

1234563 ). 但是对于 Access - 一个没有服务器部分的基于文件的数据库 - 保持单个连接打开实际上是更可取的,因为与打开新连接(创建锁定文件)相关的延迟。由于 Access 不适合与大量并发用户一起使用,因此保持连接打开的资源成本不足以成为问题。From simple tests,可以证明保持连接始终打开使后续连接的打开速度提高约 10 倍!

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

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

【讨论】:

【参考方案2】:

只是添加一些对我有用多年的信息(它有点类似于David-W-Fenton suggests)

首先,Microsoft Access(MDB、JET)的OleDbConnection使用连接池。作为Microsoft states in KB191572:

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

关于连接池,还有this blog post from Ivan Mitev表示:

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

还有微软notes in MSDN:

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

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

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

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

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

【讨论】:

+1 谢谢 uwe,除了我有点困惑 - 如果您的应用程序生命周期基本上是“整天”,因为它整天都在使用......你的意思是只打开一个连接早上 9 点到 5.30 关门?还是您所说的“应用程序生命周期”是几秒钟内的一系列请求? 我猜我的意思是......在你的三个建议中 1) 和 3) 有点说保持单个全局连接尽可能长时间打开,而 2) 说关闭它尽可能早。这取决于您所说的应用程序生命周期是什么意思? @hawbsl 是的,一开始就打开一次。退出应用时关闭。

以上是关于为啥不推荐使用一个 Public OleDbConnection?解决该错误的替代方法:打开的连接过多的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Hibernate 5 中不推荐使用条件查询?

为啥不推荐使用 (javax.servlet.)SingleThreadModel?

为啥 PoolingClientConnectionManager 中不推荐使用所有方法?

为啥 PHP 中有 openssl_public_decrypt?公钥不应该只用于加密吗?

为啥不推荐使用 [DataMember(EmitDefaultValue = false)]?

为啥不推荐使用 AngularJS $http 成功/错误方法?从 v1.6 中删除?