为啥不推荐使用一个 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 查询,尽早处理 OleDbConnection
s,就像推荐的那样。
在应用程序生命周期中尽可能晚地处置始终打开的OleDbConnection
。
这极大地加快了我的应用程序(主要是 WinForms)的速度。
请注意,这也适用于似乎也不支持连接池的 Sqlite。
【讨论】:
+1 谢谢 uwe,除了我有点困惑 - 如果您的应用程序生命周期基本上是“整天”,因为它整天都在使用......你的意思是只打开一个连接早上 9 点到 5.30 关门?还是您所说的“应用程序生命周期”是几秒钟内的一系列请求? 我猜我的意思是......在你的三个建议中 1) 和 3) 有点说保持单个全局连接尽可能长时间打开,而 2) 说关闭它尽可能早。这取决于您所说的应用程序生命周期是什么意思? @hawbsl 是的,一开始就打开一次。退出应用时关闭。以上是关于为啥不推荐使用一个 Public OleDbConnection?解决该错误的替代方法:打开的连接过多的主要内容,如果未能解决你的问题,请参考以下文章
为啥不推荐使用 (javax.servlet.)SingleThreadModel?
为啥 PoolingClientConnectionManager 中不推荐使用所有方法?
为啥 PHP 中有 openssl_public_decrypt?公钥不应该只用于加密吗?