我有一个庞大而复杂的c# Winforms应用程序。由于各种原因,它在不同的时间使OleDB连接到Access数据库。在某个函数中,我们需要移动(复制+删除)mdb文件,但它不能做,因为它是锁定的。我已经尝试了很多不同的东西来解锁/释放mdb文件,有时它工作。
但是在某个100%可复制的场景中,它不能被解锁。我们有两个全局oledb连接变量,我们在任何地方重用,为了效率,并避免到处都有1-off连接。当我们想要关闭连接时,这两个连接变量是有用的,所以我们可以删除mdb。
这是我的函数(通常工作-只是不是在这种情况下),从我们的winforms应用程序强制关闭/释放2 oledb连接:
public static void CloseOleDBConnections(bool forceReleaseAll = false) {
if ( DCGlobals.Connection1 != null )
DCGlobals.Connection1.Close();
if ( DCGlobals.Connection2 != null )
DCGlobals.Connection2.Close();
if ( forceReleaseAll ) {
DCGlobals.Connection1.Dispose();
DCGlobals.Connection2.Dispose();
OleDbConnection.ReleaseObjectPool();
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
}
我将true传递给上面的函数。
另一个想法:当然我的Winforms应用程序知道所有打开的oledbconnections。没有办法告诉c#查找和迭代所有打开的连接吗?当我关闭/退出我的应用程序-噗-打开连接到mdb被释放,我可以删除该文件。因此,.net中的某些东西知道连接并知道如何释放它——那么我如何在不退出应用程序的情况下使用相同的逻辑呢?
<发布脚本/h2>
(我知道Access很糟糕,不可扩展,等等——这是一个遗留需求,我们现在坚持使用它)。
我看过很多关于这个话题的堆栈讨论(以及其他论坛)。我已经尝试了许多建议,但都无济于事。
已处置的IDataReaders?
是否禁用了所有IDataReader对象?它们可能会阻止连接正常关闭。
跟踪方案
无论如何,您至少需要更好地跟踪所有连接。这听起来像是一个非常大的项目。您需要绝对确定所有连接都已被处理。
1。新增TrackedOleDbConnection对象
创建一个继承OleDbConnection的TrackedOleDbConnection对象,但增加了一个名为StillOpen的静态ConcurrentList。当TrackedOleDbConnection被构造时,添加到列表中,当它被处置(覆盖该函数)时,删除它。
public class TrackedOleDbConnection: OleDbConnection
{
public TrackedOleDbConnection() : base()
{
}
public TrackedOleDbConnection(string ConnectionString) : base(ConnectionString)
{
}
//You don't need to create a constructor for every overload of the baseclass, only for overloads your project uses
ConcurrentList<TrackedOleDbConnection> ActiveConnections = new ConcurrentList<TrackedOleDbConnection>();
void AddActiveConnection()
{
ActiveConnections.Add(this);
}
override void Dispose()
{
ActiveConnections.RemoveIfExists(this); //Pseudo-function
GC.SuppressFinalise(this);
}
//Destructor, to ensure the ActiveConnection is always removed, if Dispose wasn't called
~TrackedOleDbConnection()
{
//TODO: You should log when this function runs, so you know you still have missing Dispose calls in your code, and then find and add them.
Dispose();
}
}
2。不要再直接引用OleDbConnection
然后在您的解决方案中使用TrackedOleDbConnection进行简单的查找和替换。
最后,在CloseOleDBConnections函数期间,您可以访问TrackedOleDbConnection。仍然打开,看看你是否在某个地方遇到了未跟踪连接的问题。
无论您在哪里发现此类未跟踪的问题,不要使用单个中心引用,而是使用using
来确保您的连接被正确处理。
如果您唯一需要做的就是复制文件,那么可能没有必要弄乱连接。请看这个:
https://www.raymond.cc/blog/copy-locked-file-in-use-with-hobocopy/很可能ADOX没有释放到数据库的连接。确保你:
- 显式调用"关闭"ADOX连接对象
- 调用'Dispose'它们
- 调用System.Runtime.InteropServices.Marshal.FinalReleaseComObject (db.ActiveConnection);
- 调用System.Runtime.InteropServices.Marshal.Marshal.FinalReleaseComObject (db);
- 设置为none/null
同样,当某个文件句柄调用close时,关闭请求被放入一个队列中,由内核处理。换句话说,即使关闭一个简单的文件也不会立即发生。为此,您可能必须放入一个时间框循环来检查.LDB文件是否已被删除…尽管这最终需要用户等待。请寻找此方法的任何其他替代方法,尽管过去使用其他格式/连接IME是必要的。