2013-03-13 14 views
6

Jak mogę przeczytać z SQLite FAQ obsługuje wiele procesów czytania (SELECT) i tylko jednego zapisu procesu (INSERT, UPDATE, DELETE) bazy danych w dowolnym momencie w czas:Wielokrotny dostęp do pojedynczego pliku bazy danych SQLite za pośrednictwem System.Data.SQLite i C#

SQLite używa blokad czytnika/pisarza do kontrolowania dostępu do bazy danych. Gdy dowolny proces chce pisać, musi zablokować cały plik bazy danych na czas trwania aktualizacji. Ale zwykle zajmuje to tylko kilka milisekund. Inne procesy tylko czekać na pisarza, aby zakończyć następnie nadal o swojej działalności

używam System.Data.SQLite adapter za pośrednictwem C#.

Czy ktoś może mnie wyeksmitować, jak to się dzieje, że ten proces się dzieje?

Będzie to działać automatycznie i proces pisania SQLiteCommand będzie po prostu poczekać, jeśli nie ma innego pisanie SQLiteCommand już wykonywanie przez tę samą bazę danych?

A może rzuci wyjątek? Jakiego rodzaju?

Niestety ale nie znalazłem informacji o tym mechaniki :)

dziękuję.

UPDATE:

Znalazłem post mówiąc, że exception will be raised z konkretnym ErrorCode

Czy to stwierdzenie jest poprawne?

+0

Czy próbowałeś? – Default

+0

Jeszcze nie :) Wolę czytać samouczki przed kodowaniem - aby uzyskać zoptymalizowane i poprawne rozwiązania ... – bairog

+1

Jeśli wolisz "zoptymalizowane i poprawne rozwiązania", nie używaj SQLite do czegoś, z czym nie był zoptymalizowany; to świetna baza danych, ale świetna baza danych dla wielu użytkowników, której nie ma. – Tim

Odpowiedz

10

Sprawdziliśmy to sam:

stworzyłem przykładową bazę danych SQLite c:\123.db z jednej tabeli Categories zawierający dwa pola: ID (uniqueidentifier) ​​i Name (nvarchar).

Potem trochę kodu wielowątkowego naśladować wielokrotnego zapisu do bazy danych (nie zapomnij dodać System.Data.SQLite odniesienie do projektu, jeśli użyć tego kodu):

using System; 
using System.Data.SQLite; 
using System.Threading.Tasks; 

namespace SQLiteTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var tasks = new Task[100]; 

      for (int i = 0; i < 100; i++) 
      { 
       tasks[i] = new Task(new Program().WriteToDB); 
       tasks[i].Start(); 
      } 

      foreach (var task in tasks) 
       task.Wait(); 
     } 

     public void WriteToDB() 
     { 
      try 
      { 
       using (SQLiteConnection myconnection = new SQLiteConnection(@"Data Source=c:\123.db")) 
       { 
        myconnection.Open(); 
        using (SQLiteTransaction mytransaction = myconnection.BeginTransaction()) 
        { 
         using (SQLiteCommand mycommand = new SQLiteCommand(myconnection)) 
         { 
          Guid id = Guid.NewGuid(); 

          mycommand.CommandText = "INSERT INTO Categories(ID, Name) VALUES ('" + id.ToString() + "', '111')"; 
          mycommand.ExecuteNonQuery(); 

          mycommand.CommandText = "UPDATE Categories SET Name='222' WHERE ID='" + id.ToString() + "'"; 
          mycommand.ExecuteNonQuery(); 

          mycommand.CommandText = "DELETE FROM Categories WHERE ID='" + id.ToString() + "'"; 
          mycommand.ExecuteNonQuery(); 
         } 
         mytransaction.Commit(); 
        } 
       } 
      } 
      catch (SQLiteException ex) 
      { 
       if (ex.ReturnCode == SQLiteErrorCode.Busy) 
        Console.WriteLine("Database is locked by another process!"); 
      } 
     } 
    } 
} 

wyniku na mój Core2Duo E7500 jest taki, że wyjątek nigdy nie został podniesiony!

Wygląda na to, że SQLite jest wystarczająco zoptymalizowany do moich potrzeb (zablokowanie/odblokowanie jest naprawdę szybkie i zwykle zajmuje kilka milisekund, jak mówi SQLite FAQ) - Świetnie!

Należy pamiętać, że nie ma potrzeby pobierania wartości całkowitej ErrorCode dla SQLiteException - zamiast tego można użyć specjalnego pola enum ReturnCode. Wszystkie kody są opisane here.

Mam nadzieję, że ta informacja pomoże komuś.

+1

Twój kod udowodni, że wiele wątków w ramach * pojedynczego * procesu może bezproblemowo uzyskać dostęp do bazy danych SQLite. Czy byłeś w stanie sprawdzić, czy wiele różnych procesów może uzyskać dostęp do tej samej bazy danych? – pmont

+0

Cóż, najpierw przychodzi mi do głowy kompilowanie tego kodu w ** Test1.exe **, niż dodanie ** Process.Start ("Test1.exe") ** w pierwszym wierszu ** Główne ** i rekompilacja do ** Test2.exe **. Wydaje się działać, ale nigdy go nie testowałem ... – bairog

+3

Dobry pomysł! Właśnie testowałem używając tego podejścia i to działa. Dostęp wieloprocesowy działa dobrze z SQLite. – pmont

Powiązane problemy