在我的Windows 8.1(WinRT)应用程序中,我使用SQLite v 3.8.9作为数据库,而将SQLite-net作为同步执行器。它通常可以工作,但是当我尝试删除表条目时,有时会在SQLite的C ++代码中崩溃。


  (项目名称)(代码)中的第一个机会异常:Microsoft C ++异常:内存位置(位置)处的_com_error。


删除表条目



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时发生崩溃。

例外:


  SemaphoreSlim


信息:


  尝试读取或写入受保护的内存。这通常表明其他内存已损坏。


堆栈跟踪:


  在SQLite.SQLite3.SetDirectory(UInt32 directoryType,String directoryPath)
  
  在SQLite.SQLiteConnection..ctor(字符串databasePath,SQLiteOpenFlags openFlags,布尔storeDateTimeAsTicks)
  
  在SQLite.SQLiteConnection..ctor(字符串databasePath,布尔storeDateTimeAsTicks)




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

导致异常的原因是什么,我该怎么办?

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

最佳答案

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

为了确保将来不会出现此问题,我进行了以下操作:


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


工厂数据库类

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连接。即使他们正在访问其他文件。

10-08 18:43