C#操作Microsoft Access数据库后程序无法终止及内存报错问题
问题描述
我尝试使用如下C#代码读取Microsoft Access数据库。
static void getProducts() { string accessDBPath = @"C:\Users\...\dummydb.accdb"; string connectionString = @"Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" + accessDBPath; string strSQL = "SELECT * FROM Products"; try { using (OleDbConnection connection = new OleDbConnection(connectionString)) { connection.Open(); OleDbCommand command = new OleDbCommand(strSQL, connection); OleDbDataReader reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine("product name = ..."); } } } catch (OleDbException ex) { Console.WriteLine(ex.Message); } finally { Console.WriteLine("Finished"); } }
我可以正常遍历Products表(即while(reader.Read()){...}块内的内容可按预期打印输出),finally块的内容也能正常打印执行。
但该函数执行完成后,程序始终无法终止,命令行窗口处于冻结无响应状态。当我尝试在Main函数末尾通过Environment.Exit(0);强制退出程序时,会收到如下错误:
尝试读取或写入受保护的内存。这通常表明其他内存已损坏。
按照逻辑,using语句应当在数据库操作完成后自动关闭数据库连接,但实际表现仿佛连接并未被正确释放,无法定位问题原因。
编辑补充:已排查复制粘贴错误,不存在变量重复声明问题。
解决方案
核心原因
问题不是using对OleDbConnection的释放逻辑失效,而是你漏了释放OleDbCommand和OleDbDataReader持有的非托管资源。ACE OLEDB驱动是原生COM实现,OleDbDataReader会持有底层游标、数据库连接的原生内存引用,仅靠OleDbConnection的Dispose方法不会主动回收这部分资源。函数执行完成后,未释放的原生资源会在CLR卸载应用程序域时触发访问违例,直接表现就是程序卡死、强制退出时报内存受保护的错误。
除此之外,项目平台目标和ACE驱动位数不匹配、多版本ACE驱动共存也会触发完全相同的现象。
按以下步骤逐一排查修复即可:
- 所有OLEDB相关的可释放对象全部用
using块包裹,不要只包裹OleDbConnection。OleDbCommand、OleDbDataReader都实现了IDisposable接口,嵌套using可以保证所有非托管资源按顺序被正确释放,修正后的核心代码如下:
static void getProducts() { string accessDBPath = @"C:\Users\...\dummydb.accdb"; string connectionString = @"Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" + accessDBPath; string strSQL = "SELECT * FROM Products"; try { using (OleDbConnection connection = new OleDbConnection(connectionString)) { connection.Open(); using (OleDbCommand command = new OleDbCommand(strSQL, connection)) using (OleDbDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine("product name = ..."); } } } } catch (OleDbException ex) { Console.WriteLine(ex.Message); } finally { Console.WriteLine("Finished"); } }
- 检查项目平台目标和安装的ACE驱动位数是否匹配。如果安装的是64位Access Database Engine,却把项目编译为x86(32位),或者反过来装了32位引擎编译为x64,会导致ACE驱动在原生层加载异常,即使查询能正常执行,程序退出时也会触发内存损坏错误。可以打开项目属性-生成页,把平台目标强制设置为和已安装ACE驱动一致的版本(x86或x64),不要使用"Any CPU"配置,同时取消勾选"首选32位"选项。
- 如果上述修改后问题仍然存在,检查本机是否安装了多个版本的ACE OLEDB驱动(比如同时安装了2010版和2016版引擎,或者同时存在Office自带的引擎和独立安装的Database Engine包),版本冲突会导致原生DLL加载错乱,卸载多余版本只保留一个即可解决。
内容的提问来源于stack exchange,提问作者Daniel Xiao
相关产品推荐
相关产品推荐

