调用 SQLite3.SetDirectory 在 Windows 8.1 (WinRT) 上给出 System.AccessViolationException

Calling SQLite3.SetDirectory gives a System.AccessViolationException on Windows 8.1 (WinRT)

在我的 Windows 8.1 (WinRT) 应用程序中,我使用 SQLite v 3.8.9 with SQLite-net as my database, and SemaphoreSlim 作为我的同步执行器。它通常有效,但有时当我尝试删除 table 条目时,它会在 SQLite 的 C++ 代码中崩溃。

First-chance exception at (code) in (project name): Microsoft C++ exception: _com_error at memory location (location).

删除 table 个条目

private static SemaphoreSlim _mutex = new SemaphoreSlim(1,5);
public void DeleteItem(Item item)
{
    _mutex.Wait();
    using (var connection = new SQLiteConnection(Path))
    {
         connection.Delete(item);
    }
    _mutex.Release();
}

SQLite.cs

public SQLiteConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
    ...
#if NETFX_CORE
        SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
#endif
    ...
}

调用 SQLite3.SetDirectory 时发生崩溃。

异常:

System.AccessViolationException

留言:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

堆栈跟踪:

at SQLite.SQLite3.SetDirectory(UInt32 directoryType, String directoryPath)

at SQLite.SQLiteConnection..ctor(String databasePath, SQLiteOpenFlags openFlags, Boolean storeDateTimeAsTicks)

at SQLite.SQLiteConnection..ctor(String databasePath, Boolean storeDateTimeAsTicks)

问题

我猜这一定是线程问题,因为它通常可以正常工作并且有不规则的崩溃;但我找不到任何东西。

异常的原因是什么?我该如何解决?

我不认为它是损坏的内存,也许是受保护的,但我相当确定只有我的一个线程正在访问它

最后,尽管我确信一次只有一个线程访问 SQLite 数据库,但事实证明我有一些我没想到的次要代码同时被调用;这导致 AccessViolationException

为确保以后不再出现此问题,我做了以下操作:

  • 将整个 SQLite 代码移动到另一个项目以试图将其隔离。
  • 在项目中实现了半工厂模式,保证只有一个线程使用它(这也让代码看起来更好看)

工厂数据库class

public class DataBaseConnection: SQLite.SQLiteConnection
{
   private const string _path = "MySQlitePath";
   private static SemaphoreSlim _contextMutex = new SemaphoreSlim(1, 5);
   private DataBaseConnection() : base(_path)
   {
   }

   public static DataBaseConnection CreateDataBaseConnection()
   {
       _contextMutex.Wait();
       return new DataBaseConnection();
   }

   private bool disposed = false;
   protected override void Dispose(bool disposing)
   {
       if (disposed)
          return;
       if(disposing)
       {
          
       }
       disposed = true;
       base.Dispose(disposing);
       _contextMutex.Release();
    }
}

使用工厂

using (var connection = DataBaseConnection.CreateDataBaseConnection())
{
     connection.Delete(item);
}

自从用了这个以后,我再也没见过AccessViolationException


使用多个数据库连接

如果您使用多个连接(即不同的数据库路径),例如:

  • MySQlitePath_1
  • MySQlitePath_2
  • ...
  • MySQlitePath_N

您应该始终使用相同的同步机制(在我的例子中是 SemaphoreSlim)以确保 只有一个 SQLite 连接在任何给定时间打开;即使他们正在访问不同的文件。