1

我在使用 VB 编写的、在三个 IIS 服务器上运行的 ASP.NET 应用程序时遇到数据库连接错误。底层数据库是 MS Access,它位于共享网络设备上。它使用实体框架、代码优先实现和 JetEntityFrameworkProvider。

应用程序运行稳定。但是,打开数据库连接的 1000 次尝试中大约有 1 次失败,出现以下两个错误之一:

06:33:50   DbContext  "Failed to open connection at 2/12/2020 6:33:50 AM +00:00 with error: 
Cannot open database ''.  It may not be a database that your application recognizes, or the file may be corrupt.

或者

14:04:39   DbContext  "Failed to open connection at 2/13/2020 2:04:39 PM +00:00 with error: 
Could not use ''; file already in use.

一秒钟后,通过刷新 (F5),错误消失并再次起作用。

有关环境和使用代码的详细信息。

连接字符串

<add name="DbContext" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=x:\thedatabase.mdb;Jet OLEDB:Database Password=xx;OLE DB Services=-4;" providerName="JetEntityFrameworkProvider" />

数据库上下文管理

应用程序使用公共属性来访问 DbContext。DbContext 在请求的生命周期内保存在 HttpContext.Current.Items 集合中,并在请求结束时被释放。

Public Shared ReadOnly Property Instance() As DbContext
    Get
        SyncLock obj
            If Not HttpContext.Current.Items.Contains("DbContext") Then
                HttpContext.Current.Items.Item("DbContext") = New DbContext()
            End If

            Return HttpContext.Current.Items.Item("DbContext")
        End SyncLock
    End Get
End Property

BasePage 初始化并释放 DbContext。

Protected Overrides Sub OnInit(e As EventArgs)
    MyBase.OnInit(e)
    DbContext = Data.DbContext.Instance
    ...
End Sub

Protected Overrides Sub OnUnload(e As EventArgs)
    MyBase.OnUnload(e)
    If DbContext IsNot Nothing Then DbContext.Dispose()
End Sub

我试过的

解决上述错误消息的许多关于 SO 的问题通常涉及无法建立与数据库的连接——它们根本无法连接。这与本案不同。连接在 99.99% 的时间内都有效。

除此之外,我还检查了:

  • 权限:对 .mdb(数据库)和 .ldb(锁定文件)所在的共享授予完全访问权限。
  • 网络连接:共享设备没有连接问题;这是一个千兆 LAN 连接
  • 未达到最大并发连接数 255
  • 未超过数据库的最大大小(db 只有 5 MB)
  • 按照MS Dev-Net 帖子中的建议,将编译选项从“Any CPU”更改为“x86”

Quote: 我得到相同的“无法打开数据库''”错误,但完全随机(似乎)。MDB 文件小于 1Mb,因此对于 2Gb 限制没有问题,因为这个错误经常提到。它在 32 位版本的 Windows 上工作 100%,但我发现问题出在 64 位安装上。该应用程序被编译为“任何 CPU”。我将编译选项从“Any CPU”更改为“x86”,问题就消失了。

到目前为止没有任何帮助。

为了收集更多信息,我将一个 Nlog 记录器附加到 DbContext,它将所有数据库操作和查询写入日志文件。

Shared Log As Logger = LogManager.GetLogger("DbContext")
Me.Database.Log = Sub(s) Log.Debug(s)

调查日志我发现当上述错误之一发生在一台服务器上时,另一台服务器(总共 3 台)同时关闭了数据库连接。这里有两个对应于上述错误的例子:

06:33:50   DbContext  "Closed connection at 2/12/2020 6:33:50 AM +00:00
14:04:39   DbContext  "Closed connection at 2/13/2020 2:04:39 PM +00:00

假设

当 DbContext 的所有连接都已关闭时,相应的记录将从 .ldb 锁定文件中删除。当打开与数据库的连接时,将在锁定文件中添加一条记录。当这两个事件同时发生时,来自两个不同的服务器,对 .ldb 锁定文件存在写入冲突,从而导致出现上述错误。

问题

任何人都可以确认或证明这是错误的吗?有没有人经历过这种行为?也许我错过了其他东西。感谢您对此的意见和经验。

如果我的假设是真的,一个解决方案可能是使用一个帮助类来访问 db,它会捕获并处理这个错误,等待最短的时间段并再次尝试。

但这感觉有点不对劲。因此,我也愿意接受有关“适当”解决方案的建议。

编辑: “正确”的解决方案将使用 DBMS 服务器(如下面的评论中所述)。我知道这一点。现在,我不得不处理这个设计错误,而不是对此负责。此外,我无法在短期内改变它。

4

2 回答 2

1

由于篇幅原因,我将其写为一个回答,但这并不是一个真正的答案。

这肯定是 OleDb 提供程序的问题。
我认为这是一个共享问题。你可以做一些尝试:

  • 使用较新的 OleDb 提供程序而不是Microsoft.Jet.OLEDB.4.0. (如果您尝试过 64 位,您可能已经尝试过其他提供商,因为 Jet.OLEDB.4.0 仅为 32 位)
  • 实施重试机制new DbContext()
  • 阅读您的测试,这可能不是您的情况。我认为 Dispose 并不总是在 Jet.OLEDB.4.0 连接上正常工作。我在测试中注意到它,并使用不同的测试引擎解决了它。在放弃之前我使用了这段代码
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true); GC.WaitForPendingFinalizers();
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
    正如你可以理解阅读这段代码,他们是尝试和最新的解决方案是改变测试引擎。

  • 如果您的应用程序不太忙,您可以尝试使用不同的机制(例如使用锁定文件)锁定数据库。这与重试并没有什么不同new DbContext()

  • 我记得在 90 年代后期,我遇到了一个与磁盘共享操作系统相关的问题(我使用的是 Novel Netware)。实际上,我没有在网络共享上使用 mdb 文件的经验。您可以尝试将 mdb 移动到与 Windows 共享的文件夹中
  • 实际上,我仅将 Access 数据库用于测试。如果您确实需要使用单个文件数据库,您可以尝试其他解决方案:SQL Lite(您需要一个库,也是我编写的,首先应用代码https://www.nuget.org/packages/System.Data。 SQLite.EF6.Migrations/ ) 或 SQL Server CE
  • 使用 DBMS 服务器。这肯定是最好的解决方案。作为作者,JetEntityFrameworkProvider我认为单文件数据库非常适合单用户应用程序(对于这个应用程序,我建议使用 SQL Lite)、测试(我认为测试JetEntityFrameworkProvider非常好)、传输数据或只读应用程序。在其他情况下,使用 DBMS 服务器。如您所知,使用 EF,您可以毫不费力地从 JetEntityFrameworkProvider 更改为 SQL Server 或 MySql。
于 2020-02-19T07:33:41.920 回答
0

你在设计阶段出错了:MS Access 数据库引擎不适合 ASP.Net 站点,这在多个地方都有明确说明,例如,详细信息下的官方下载页面

Access 数据库引擎 2016 Redistributable 不打算用于......供......从服务器端 Web 应用程序(如 ASP.NET)调用的程序使用

如果您确实必须使用 Access 数据库,您可以运行一个帮助程序类,在出现常见错误时重试。但我不推荐它。

此处正确的解决方案是使用表现出无状态行为的不同 RDBMS。我推荐 SQL Server Express,它有局限性,但如果你超过了这些,你将远远超出 Access 支持的范围,并且不会导致这样的错误。

于 2020-02-19T08:27:03.433 回答