2011-04-27 131 views
4

我寫了一個簡單的應用程序(稱爲app1),它讀取SQLite數據庫並在GridView中顯示內容。我有一個單獨的C#控制檯應用程序(app2)需要寫入同一個數據庫。問題是app2失敗,出現「數據庫已鎖定」錯誤。我可以看到,只要我啓動app1,就會創建一個userdb-journal文件。我認爲問題是,app1打開數據庫,但不釋放它?這是我用於填充綁定到app1中的網格的表的代碼。C#:SQLite數據庫始終鎖定

public DataTable GetAllPeople() 
    { 
     var connectionString = "Data Source=" + dbPath + ";Version=3"; 

     using (SQLiteDataAdapter sqlDataAdapter = 
      new SQLiteDataAdapter("SELECT id,FirstName,LastName,Address FROM Users", 
            connectionString)) 
     { 
      using (DataTable dataTable = new DataTable()) 
      { 
       sqlDataAdapter.Fill(dataTable); 
       // code to add some new columns here 

       return dataTable; 
      } 
     } 
    } 

這裏是填充GridView控件的代碼:

private void Form1_Load(object sender, EventArgs e) 
    { 
     UserDatabase db = new UserDatabase(); 
     db.Initialize(); 
     dataGridView1.DataSource = db.GetAllPeople(); 

    } 

我怎樣才能解決事情,所以APP 2可以讀取並同時APP1運行寫入數據庫?

編輯 看起來像那個日誌文件只是由app2創建的。我只注意到app1在運行時數據庫鎖定錯誤,但也許app1是一個紅色的鯡魚。 App2是多線程的。也許我應該開始一個關注app2和多線程訪問的新問題?

編輯 感謝您的所有意見。我已經鎖定了所有數據庫訪問,並將所有內容都包含在使用中。現在似乎都在工作。

+0

SQLite日誌是在您將*寫入數據庫時​​創建的,不會讀取它。而'GetAllPeople'只能從數據庫中讀取,所以它可能暫時只獲得一個單獨的共享鎖,然後返回。你確定你沒有寫你的分貝在你的app1? – Groo 2011-04-27 11:29:16

+0

你是對的。我錯了。看起來這個日誌文件只是由app2創建的。我只注意到app1在運行時數據庫鎖定錯誤,但也許app1是一個紅色的鯡魚。 App2是多線程的。也許我應該開始一個關注app2和多線程訪問的新問題? – RogerS 2011-04-27 12:14:25

+0

@RogerS:你應該專注於你寫入數據庫的部分,那就是它被鎖定的部分。檢查配置的讀取超時,並確保您正確處理連接。很可能有一部分代碼執行冗長的插入或更新操作,並將文件鎖定時間過長。 – Groo 2011-04-27 13:34:18

回答

0

您是否要求SQLITE等待並再次嘗試db是否被鎖定?以下是如何做到在C

// set SQLite to wait and retry for up to 100ms if database locked 
    sqlite3_busy_timeout(db, 100); 

的一點是,SQLITE鎖定DB簡單,當它被訪問。如果另一個線程或進程在阻塞時訪問它,默認情況下SQLITE會返回一個錯誤。但是,您可以讓它等待,並通過上述呼叫自動重試。這解決了許多這類問題。

+0

謝謝,看起來非常有用。你知道如何從C#做到這一點? – RogerS 2011-04-27 13:12:37

+0

@RogerS我不使用C#多。我的猜測是:將'busy_timeout = 100'添加到連接字符串中。 – ravenspoint 2011-04-27 13:49:14

+0

位遲了,但以防萬一有人需要它:如果您正在使用System.Data.SQLite.dll,您可以使用SQLiteConnectionStringBuilder類及其DefaultTimeout屬性來定義超時。 – 2012-02-24 16:08:30

2

以下是代碼,在連接字符串構建器上輕鬆設置參數,並使用它構建SQLiteConnection。

SQLiteConnectionStringBuilder connBuilder = new SQLiteConnectionStringBuilder(); 
     connBuilder.DataSource = filePath; 
     connBuilder.Version = 3; 
     connBuilder.CacheSize = 4000;    
     connBuilder.DefaultTimeout = 100; 
     connBuilder.Password = "mypass"; 


     using(SQLiteConnection conn = new SQLiteConnection(connBuilder.ToString())) 
     { 
      //... 
     } 

問候。