2014-05-20 75 views
12

我們有一個.NET Windows Service將WCF服務公開給用戶界面和我們系統的其他部分。它的目標是.NET Framework 4.5並使用SQLite 1.0.92二進制文件與底層SQLite數據庫進行通信。但是,運行SQLite.Interop.dll中的AccessViolationException(通過Windows事件查看器找到)一段時間後,Windows服務崩潰(自動停止)。我遇到了有關Connection close中的這個異常的文章,但在我們所有的情況下,我們在使用WCF服務公開的方法查詢或寫入數據庫時​​遇到此異常。堆疊跟蹤如下:WCF服務中的SQLite AccessViolationException

Application: OurServer.exe 
Framework Version: **v4.0.30319** 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.AccessViolationException 
Stack: 
    at System.Data.SQLite.UnsafeNativeMethods.sqlite3_bind_int(IntPtr, Int32, Int32) 
    at System.Data.SQLite.UnsafeNativeMethods.sqlite3_bind_int(IntPtr, Int32, Int32) 
    at System.Data.SQLite.SQLite3.Bind_Int32(System.Data.SQLite.SQLiteStatement, System.Data.SQLite.SQLiteConnectionFlags, Int32, Int32) 
    at System.Data.SQLite.SQLiteStatement.BindParameter(Int32, System.Data.SQLite.SQLiteParameter) 
    at System.Data.SQLite.SQLiteStatement.BindParameters() 
    at System.Data.SQLite.SQLiteCommand.GetStatement(Int32) 
    at System.Data.SQLite.SQLiteDataReader.NextResult() 
    at System.Data.SQLite.SQLiteDataReader..ctor(System.Data.SQLite.SQLiteCommand, System.Data.CommandBehavior) 
    at System.Data.SQLite.SQLiteCommand.ExecuteReader(System.Data.CommandBehavior) 
    at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(System.Data.CommandBehavior) 
    at DataAccess.Sqlite.ExecuteCommand(System.Collections.ObjectModel.Collection`1<System.String>, System.Collections.ObjectModel.Collection`1<System.Data.Common.DbParameter[]>) 
    at Data.Settings.Save(System.Collections.ObjectModel.Collection`1<Common.Operation>) 
    at DynamicClass.SyncInvokeSaveOperation(System.Object, System.Object[], System.Object[]) 
    at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(System.Object, System.Object[], System.Object[] ByRef) 
    at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean) 
    at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(System.ServiceModel.Channels.RequestContext, Boolean, System.ServiceModel.OperationContext) 
    at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(System.ServiceModel.Channels.RequestContext, System.ServiceModel.OperationContext) 
    at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(System.IAsyncResult) 
    at System.Runtime.Fx+AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult) 
    at System.Runtime.AsyncResult.Complete(Boolean) 
    at System.Runtime.InputQueue`1+AsyncQueueReader[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Set(Item<System.__Canon>) 
    at System.Runtime.InputQueue`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].EnqueueAndDispatch(Item<System.__Canon>, Boolean) 
    at System.Runtime.InputQueue`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].EnqueueAndDispatch(System.__Canon, System.Action, Boolean) 
    at System.ServiceModel.Channels.SingletonChannelAcceptor`3[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Enqueue(System.__Canon, System.Action, Boolean) 
    at System.ServiceModel.Channels.ConnectionDemuxer+CompleteSingletonPreambleAndDispatchRequestAsyncResult.OnPreambleComplete(System.IAsyncResult) 
    at System.Runtime.Fx+AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult) 
    at System.Runtime.AsyncResult.Complete(Boolean) 
    at System.ServiceModel.Channels.ServerSingletonPreambleConnectionReader+CompletePreambleAsyncResult.OnWriteCompleted(System.Object) 
    at System.ServiceModel.Channels.SocketConnection.OnSendAsync(System.Object, System.Net.Sockets.SocketAsyncEventArgs) 
    at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
    at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(System.Net.Sockets.SocketError, Int32, System.Net.Sockets.SocketFlags) 
    at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 
    at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 

我們使用來自 「源碼-netFx45二進制束-Win32-2012-1.0.92.0」(來自http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki下載)SQLite的組件。這些程序集作爲Windows服務的一部分捆綁在一起,不在GAC中。這種行爲在32位和64位機器上都是一致的。僅供參考,我們不使用混合模式組件。

我們的連接字符串:

Data Source=ourapp.db;Version=3;New=False;Compress=True;PRAGMA cache_size=20000; PRAGMA page_size=32768; PRAGMA synchronous=off" 

和SQLite數據庫文件是Windows的 「ProgramData」 文件夾中。

stacktrace將Framework版本顯示爲「v4.0.30319」,而我們在服務的應用程序配置中將目標版本顯式設置爲4.5。但是,該機器安裝了兩個版本。

另外,我編寫了一個簡單的控制檯應用程序,該應用程序從多個線程調用相同的WCF服務方法,但無法模擬相同的AccessViolationException。因此,我不認爲這可能是一個負載或併發訪問相關的問題。這個例外似乎是隨機的,除了運行服務並等待它發生之外,我們沒有辦法一貫地重新產生問題。

任何可能會導致此問題的指針非常感謝。

UPDATE:

代碼使用ExecuteCommand的兩個變種:

public int ExecuteCommand(string query, params DbParameter[] parameters) 
    { 
     try 
     { 
      this.result = -1; 
      this.OpenConnection(); 
      this.command = new SQLiteCommand(query, this.connnection); 
      this.HandleParameters(parameters); 
      this.result = this.command.ExecuteNonQuery(); 
     } 
     catch (Exception ex) 
     { 
      this.result = -1; 
     } 
     finally 
     { 
      if (this.command != null) 
      { 
       this.command.Dispose(); 
      } 

      this.CloseConnection(); 
     } 

     return this.result; 
    } 


    public int ExecuteCommand(Collection<string> queries, Collection<DbParameter[]> parameters) 
    { 
     try 
     { 
      this.result = -1; 
      this.OpenConnection(); 
      this.command = new SQLiteCommand(); 
      this.command.Connection = this.connnection; 
      this.transaction = this.connnection.BeginTransaction(); 

      for (int i = 0; i < queries.Count; i++) 
      { 
       this.command.Parameters.Clear(); 
       this.command.CommandText = queries[i]; 
       this.command.CommandTimeout = this.timeOut; 
       this.command.Transaction = this.transaction; 

       DbParameter[] cmdParams = new DbParameter[] { }; 
       if (parameters != null) 
       { 
        cmdParams = parameters[i]; 
       } 

       this.HandleParameters(cmdParams); 
       this.result += this.command.ExecuteNonQuery(); 
      } 

      this.transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      if (this.transaction != null) 
      { 
       this.transaction.Rollback(); 
      } 

      this.result = -1; 
     } 
     finally 
     { 
      if (this.command != null) 
      { 
       this.command.Dispose(); 
      } 

      this.CloseConnection(); 
     } 

     return this.result; 
    } 

更新2:代碼保存方法

Collection<DbParameter[]> dbparameters = new Collection<DbParameter[]>(); 
    DbParameter[] dbparams; 
    SQLiteParameter sqlparams; 
    Collection<string> queries = new Collection<string>(); 
    int icount = 0; 

    foreach (Operation operation in operations) 
    { 
     icount = 0; 
     dbparams = new DbParameter[4]; 

     queries.Add("UPDATE table1 SET col1 = @Col1, col2 = @col2, " + 
        "Timestamp = @Timestamp WHERE Id = @Id"); 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Timestamp"; 
     sqlparams.Value = string.Format(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss}", operation.Timestamp); 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Id"; 
     sqlparams.Value = operation.Id; 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Col1"; 
     sqlparams.Value = operation.Col1; 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Col2"; 
     sqlparams.Value = operation.Col2; 
     dbparams[icount++] = sqlparams; 


     dbparameters.Add(dbparams); 
    } 


    return (DataAccess.Sqlite.ExecuteCommand(queries, dbparameters) > -1); 
+0

你可以顯示一些'DataAccess.SqlLite.ExecuteCommand'和'Data.Settings.Save'方法的代碼嗎? – nvoigt

+0

我已經使用ExecuteCommand的代碼更新了帖子。 Save方法組成查詢及其參數,並調用接受查詢集合的重載方法。 – Ananth

+0

Save方法的更多更新 – Ananth

回答

1

錯誤與供應商失去軌跡一致其中Connections已打開:

  • 試圖關閉不存在
  • 嘗試使用不存在

錯誤看起來像連接池的問題,但您的連接字符串不使用連接池連接的連接,它默認關閉。

是否有其他操作訪問相同的數據庫打開連接池功能?

您必須做的第一件事是記錄異常。

1

您的課程可能不是線程安全的。檢查多個線程是否不同時調用Save方法。

如果它是您類的私有成員,還要確保您實現了IDisposable來處置SQLiteConnection對象。