使用 Access SQL 函数时,Microsoft Access ODBC 驱动程序导致访问冲突

Posted

技术标签:

【中文标题】使用 Access SQL 函数时,Microsoft Access ODBC 驱动程序导致访问冲突【英文标题】:Microsoft Access ODBC driver causes access violation when Access SQL functions are used 【发布时间】:2020-02-24 11:33:54 【问题描述】:

我在本地计算机上使用 Microsoft Access ODBC 驱动程序(由 AccessDatabaseEngine_X64.exe 安装)在较旧的 Access 数据库上运行“SQL”语句。这里一切正常。

但现在我将其部署到 Docker 容器(使用 mcr.microsoft.com/windows:1809-amd64)作为基础映像。我的 dockerfile 安装了 .NET Core 和 AccessDatabaseEngine_X64.exe。但是当我在容器上运行我的应用程序时,它执行了数百条“SQL”语句就好了,但突然得到一个 AccessViolationException。在一遍又一遍地运行相同的事务脚本后,我最终发现它总是在同一个查询上崩溃——并且查询包含 IsNull()。

我确认容器上的驱动程序文件与我的本地机器匹配(均为 64 位)。对于测试,我在本地机器和容器上使用完全相同的数据库——但这并不重要,因为数据库可以为空以获取访问冲突。

我已将测试应用程序简化为这个简单的程序:

const string connectionString = @"Driver=Microsoft Access Driver (*.mdb, *.accdb);Dbq=db\Test.mdb";
const string sql = "SELECT IsNull(null)";
var odbcConnection = new OdbcConnection(connectionString);
odbcConnection.Open();
odbcConnection.Execute(sql); // Dapper

在我的本地机器上它工作正常,但在容器中它崩溃并出现 AccessViolationException。这是容器输出中的异常:

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Interop+Odbc.SQLExecDirectW(System.Data.Odbc.OdbcStatementHandle, System.String, Int32)
   at Interop+Odbc.SQLExecDirectW(System.Data.Odbc.OdbcStatementHandle, System.String, Int32)
   at System.Data.Odbc.OdbcStatementHandle.ExecuteDirect(System.String)
   at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(System.Data.CommandBehavior, System.String, Boolean, System.Object[], SQL_API)
   at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(System.Data.CommandBehavior, System.String, Boolean)
   at System.Data.Odbc.OdbcCommand.ExecuteNonQuery()
   at Dapper.SqlMapper.ExecuteCommand(System.Data.IDbConnection, Dapper.CommandDefinition ByRef, System.Action`2<System.Data.IDbCommand,System.Object>)
   at Dapper.SqlMapper.ExecuteImpl(System.Data.IDbConnection, Dapper.CommandDefinition ByRef)
   at Dapper.SqlMapper.Execute(System.Data.IDbConnection, System.String, System.Object, System.Data.IDbTransaction, System.Nullable`1<Int32>, System.Nullable`1<System.Data.CommandType>)

我想澄清一下,我在容器上运行数百个其他查询都很好,但是当 IsNull() 位于命令文本中的任何位置时,它总是会失败。

所以我很好奇并尝试了其他一些 Microsoft Access 函数,例如 Now() 和 IsNumeric(1030)。那些也会抛出 AccessViolationException!

我真的很纠结如何继续解决这个问题。为什么司机的行为不一样?驱动程序不支持 Microsoft Access 功能,还是我需要添加依赖项才能获得完整的 Microsoft Access 支持?

谢谢

【问题讨论】:

IIRC Access 需要 .NET Framework,但通常安装程序也应该为您安装它。尝试将其安装在 .NET Core 旁边。 我在安装 .NET Core 之前安装、更新和更新了 .NET Framework 4.8,不幸的是,这并没有解决问题。我还尝试按照此处(itninja.com/software/microsoft/access-runtime/2016-1)的描述安装 acces-s-runtime_4288-1001_x86_en-us.exe,但这也无济于事...... 啊,那就没有线索了,除了您可以考虑安装完整的 Access Runtime,因为其中一些功能是由 Access 应用程序而不是数据库引擎提供的。请注意,Access 数据库引擎的静默安装会跳过几项检查(例如检查不同位数的冲突 Office 安装),如果您在手动安装时一切正常,我只会切换到静默安装。 啊,我只想评论一下,我实际上安装了 x64 访问运行时,来自这里 (download.microsoft.com/download/D/B/D/…)。我在之前的评论中提到过,我认为你提到过,我引用了 x86。那只是附加链接的复制粘贴。此外,手动安装在这里不是一个选项,因为它会转到 Docker 容器。但是,检查 Office 冲突(等)不是问题,因为目标容器是全新的 Windows 安装。 是的,我知道最终它需要进行静默安装,但出于调试目的,我建议手动安装,因为在静默安装期间可能会跳过更多检查。 【参考方案1】:

我收到访问冲突的原因是因为我需要安装 Microsoft Access 运行时。 Access 数据库引擎和 Microsoft Access 运行时都是必需的——如果只安装了数据库引擎连接到 MDB 工作,但你不能做任何花哨的事情。

现在,在 Docker 容器上正确安装 Microsoft Access 运行时已不是一件小事。为此,这个问题有一个详细的答案:How to install Access Runtime on a Docker container?

我想补充一点,我不需要任何其他依赖项即可使其端到端工作。不是 VC Runtime,也不是 .NET Framework。

希望这对将来的其他人有所帮助。

【讨论】:

以上是关于使用 Access SQL 函数时,Microsoft Access ODBC 驱动程序导致访问冲突的主要内容,如果未能解决你的问题,请参考以下文章

Access SQL 中的 CDec 的行为与从 Access VBA 中使用时的行为不同

如何使用 PHP、SQL 和 Microsoft Access 将另一个表中的 select max 函数和用户输入的变量插入表中?

MS-Access 获取字段值,通过 VBA 函数运行,并发送到 SQL

是否有与 SQL Server NewId() 函数等效的 Access?

MS Access Sql 查询不是聚合函数的一部分。使用计数功能

在 Access 2007 SQL 中的 Group By 聚合函数中计数 Distinct