OleDB连接到Microsoft Access数据文件的间歇性“超出系统资源”exception
运行我的代码时,我遇到了看似随机的“超出系统资源”exception。 我的程序背后的想法是第三方软件不断将数据写入Microsoft Access数据库文件(.res) – 大约每30秒我的代码从该文件读取数据,对其执行一些操作,并写入结果到我们的数据库。 不幸的是我无法改变第三方软件将数据写入文件的方式,我坚持使用Access数据文件。
在运行通过Click-Once发布安装的WinForms程序的生产系统以及我的开发系统上的控制台测试程序中都会发生此错误。 即使在运行返回单个整数的查询而没有其他程序或线程正在触及位于我本地磁盘上的文件时,我也会收到exception。
例外信息:
System.Data.OleDb.OleDbException (0x80004005): System resource exceeded. at System.Data.OleDb.OleDbCommand.ExecuteCommandTextErrorHandling(OleDbHResult hr) at System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(tagDBPARAMS dbParams, Object& executeResult) at System.Data.OleDb.OleDbCommand.ExecuteCommandText(Object& executeResult) at System.Data.OleDb.OleDbCommand.ExecuteCommand(CommandBehavior behavior, Object& executeResult) at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method) at System.Data.OleDb.OleDbCommand.ExecuteScalar() ...
重现问题的示例代码:
string connectionString = @"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = C:\datafile.res"; string commandText = "SELECT MIN(Data_Point) FROM Channel_Normal_Table WHERE Test_ID = 1"; int connectionCounter = 0; object result; while (true) { using (OleDbConnection connection = new OleDbConnection(connectionString)) { connection.Open(); connectionCounter++; using (OleDbCommand command = new OleDbCommand(commandText, connection)) { result = command.ExecuteScalar(); } connection.Close(); } }
不幸的是,exception不是确定性的 – 我已经看到它发生在从第4个命令执行到第6149个的任何地方,在同一个文件上使用相同的代码。 它总是出现在command.ExecuteScalar()行上。 如果此代码中存在资源泄漏,请帮我找到它。
我已经尝试安装http://support.microsoft.com/kb/2760394上找到的修补程序(并进行了所需的注册表更改),但它没有解决问题。 任何建议都将受到赞赏和积极追求。
这适用于Windows 7,C#4.0(控制台和WinForms),4 GB RAM
在你的情况下我会尝试几件事:
- 由于数据库的用户只是应用程序,我会以独占模式打开数据库,这将有助于驱动程序摆脱管理锁文件的开销(并且还应加快对数据库的访问)。
// Share Mode=12 - exclusive mode (16 for multi-user) string constr = @"Provider=Microsoft.ACE.OLEDB.12.0;" + "Mode=12;Data Source = C:\datafile.res;user id=;password=;";
- 程序启动时打开与Access数据库的连接,并在应用程序关闭之前保持打开状态。
在紧密循环中,锁定文件问题蔓延并导致各种难以调试的奇怪问题。
只需在Access数据库中有一个包含单个记录的虚拟表,然后打开该表以读取记录,但保留对该连接的永久引用:
private OleDbCommand PermanentCommand; void KeepLinkOpen() { if (PermanentCommand == null || PermanentCommand.Connection == null || PermanentCommand.Connection.State == System.Data.ConnectionState.Closed) { OleDbConnection conn = new OleDbConnection(connectionString); conn.Open(); PermanentCommand = new OleDbCommand("SELECT * FROM DummyTable", conn); PermanentCommand.ExecuteReader(System.Data.CommandBehavior.Default); } } void Disconnect() { if (PermanentCommand != null) { if (PermanentCommand.Connection != null) { PermanentCommand.Connection.Close(); } PermanentCommand.Dispose(); PermanentCommand = null; } }