我必须处理另一个开发人员制作的项目。一个项目Win Form,使用Visual Basic代码,使用MS Access作为数据库和一些OleDbConnections。有一个错误:有时应用程序无法打开OleDbConnection,因为数据库上的连接数已达到最大值。我知道使用连接的最佳方式是:
Using cn As New OleDbConnction(s)
...
cn.Close()
End Using
但在该项目中,有许多类可以使用数据库,在其中许多类中,有具有"Friend"可见性的OleDbConnections,它们在不同的时间打开和关闭。因此,不可能将所有的OleDbConnection都放在Using构造中,而且很难找到"忘记"关闭其中一个OleDbConnections的操作。
一个可能的解决方案是只使用一个唯一的公共OleDbConnection,并在打开它之前检查它是否尚未打开。但有人告诉我,这是一种非常糟糕的做法。我想他告诉了我这场演出的情况,但我不太清楚。你能告诉我为什么一个唯一的公共OleDbConnection如此不受欢迎吗?对我来说,你有一个"简单"的解决方案吗?非常感谢。Pileggi
根据您的描述,我看到了可能导致您的问题的几个问题:
- 嵌套连接:
打开彼此之间的多个连接 - 打开/释放连接过快:
正如David-W-Fenton所提到的,通过访问,每次打开/关闭单个连接时,都会创建/删除锁定文件。此操作非常缓慢,如果您快速打开/关闭应用程序中的数据库(执行大量原子查询),则可能会出现此问题
调查和解决问题的几种可能方法:
跟踪所有打开/关闭调用
添加一些调试跟踪,每次打开和关闭连接时都会显示这些跟踪
它将允许您检测嵌套连接以及连接池被浪费的位置。
强制连接轮询一个简单的"修复"方法可能是在连接字符串中显式设置连接池。这应该是默认行为,所以也许它不会解决你的问题,但它很简单,没有理由不尝试:
OLE DB Services=-1
使用连接管理器类为您创建/释放连接
用您自己的代码替换所有显式创建的新OleDbConnection和关闭操作。这将允许您在整个应用程序中始终重复使用单个现有连接,并允许您通过将行为集中在一个地方来快速调整整个应用程序。
那么,为什么通常不赞成使用单一连接呢
通常,您不应该在整个应用程序中保持连接打开,因为它们会迫使数据库服务器为您保留可用资源,并且会减少可以连接的客户端数量(可用的连接数量总是有限的)
不过,对于Access(一个没有服务器部分的基于文件的数据库)来说,保持单个连接打开实际上更可取,因为打开新连接(创建锁定文件)会延迟。由于Access不适合与大量并发用户一起使用,因此保持连接打开的资源成本不足以成为问题
从简单的测试中可以看出,保持连接始终打开可以使后续连接的打开速度快10倍!OleDb驱动程序为您提供连接池,因此在释放连接时可以重用连接。
通过保持连接和数据库操作的小型化和包容性,您在使用线程时不太可能遇到并发问题。如果使用到数据库的同一管道执行多个操作,则保持全局连接可能会成为一个问题。
只是添加了一些多年来对我有效的信息(这与David-W-Fenton的建议有点相似)
首先,OleDbConnection
到Microsoft Access(MDB,JET)是而不是使用连接池。正如微软在KB191572中所说:
使用Jet OLE DB提供程序和ODBC驱动程序的连接不是池,因为这些提供者和驱动程序不支持池。
关于连接池,还有伊万·米捷夫的这篇博客文章说:
那么这意味着什么呢?很明显主动打开的连接使测试具有多重连接关闭和打开的速度要快得多(2-3次)。唯一可能的对我的解释是,每次都会释放连接池没有活动连接。我必须做进一步的调查并在Microsoft Data Access中阅读类似Pooling的内容组件。或者可能只是为了保持一个打开的连接保持水池的活力。这将是丑陋的,但它仍然是一个好足够的变通方法!如果有人有更好的想法,请分享。
微软在MSDN上的注释:
ADO Connection对象隐式使用IDataInitialize。然而这意味着您的应用程序需要至少保留一个始终为每个唯一用户实例化连接对象。否则,当最后一个Connection对象因为该字符串是闭合的。
基于所有这些和我自己的测试,我的解决方案即使使用Microsoft Access数据库也要"模拟"连接池,大致遵循以下步骤:
- 在应用程序生命周期中尽早向Access数据库打开一个
OleDbConnection
- 执行正常的SQL查询,尽可能早地处理
OleDbConnection
,就像建议的那样 - 请确保在应用程序生命周期中始终尽可能晚地打开
OleDbConnection
这大大加快了我的应用程序(主要是WinForms)的速度。
请注意,这也适用于Sqlite,它似乎也不支持连接池。