2017-11-01 7 views
3

Ich arbeite an der Portierung einer Reihe von Paradox-Tabellen zu SQLite. Um dies zu tun, habe ich eine Testanwendung erstellt, die (etwas) das aktuelle Nutzungsszenario simuliert: mehrere Benutzer, die auf die gleiche DB-Datei zugreifen und simultane Lese- und Schreibvorgänge ausführen.Tabellensperren in SQLite, auf die von FireDAC zugegriffen wird

Die Anwendung ist sehr einfach: Es startet mehrere Threads, die jeweils eine Verbindung erstellen, öffnet eine Tabelle und wird nach dem Zufallsprinzip zu lesen, zu aktualisieren oder in die Tabelle einfügen.

Fast sofort, Die Anwendung entdeckt einen Fehler "Datenbank Tabelle gesperrt". Ich habe versucht, einige Dinge zu versuchen, um es zu umgehen, aber nichts scheint zu funktionieren. Was mache ich falsch ?

Hier ist der Code intern auf die Gewinde:

procedure testDB(TargetFolder: string); 
var 
    Conn: TFDConnection; 
    Table: TFDTable; 
    i: Integer; 
begin 
    randomize; 
    Conn := TFDConnection.Create(nil); 
    try 
    Conn.DriverName := 'SQLite'; 
    Conn.LoginPrompt := false; 
    Conn.Params.clear; 
    Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb'); 
    Conn.Params.Add('DriverID=SQLite'); 
    // all this is the result of several attemp to fix the table locking error. none worked 

    Conn.Params.Add('LockingMode=Normal'); 
    Conn.Params.Add('Synchronous=Normal'); 
    Conn.UpdateOptions.UpdateMode := TUpdateMode.upWhereAll; 
    Conn.UpdateOptions.LockWait := True; 
    Conn.UpdateOptions.LockMode := TFDLockMode.lmPessimistic; 
    Conn.UpdateOptions.LockPoint := TFDLockPoint.lpImmediate; 
    Conn.UpdateOptions.AssignedValues := [uvLockMode,uvLockPoint,uvLockWait]; 
    Conn.Open(); 
    Conn.ExecSQL('CREATE TABLE IF NOT EXISTS ''test'' (''ID'' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,''data1'' TEXT NOT NULL,''data2'' INTEGER NOT NULL)'); 
    Table := TFDTable.Create(nil); 
    try 
     table.Connection := Conn; 
     while True do 
     begin 
     case Trunc(Random(10)) of 
      0..3: 
      begin 
      table.Open('test'); 
      try 
       if table.Locate('data1', 'name'+intToStr(Trunc(Random(10))),[TLocateOption.loCaseInsensitive]) then 
       begin 
       table.Edit; 
       table.FieldByName('data2').AsInteger := table.FieldByName('data2').AsInteger + 1; 
       table.Post; 
       end; 
      finally 
       table.close; 
      end; 
      end; 
      4..8: 
      begin 
      table.Open('test'); 
      try 
       i := Trunc(Random(10)); 
       if not table.Locate('data1', 'name'+ i.ToString,[TLocateOption.loCaseInsensitive]) then 
       begin 
       table.AppendRecord([null, 'name'+ i.ToString, 0]); 
       end; 
      finally 
       table.close; 
      end; 
      end 
     else 
      break; 
     end; 
     end; 
    finally 
     FreeAndNil(Table); 
    end; 
    finally 
    FreeAndNil(Conn); 
    end; 
end; 
+3

In [dieses Kapitel] (http://docwiki.embarcadero.com/RADStudio/en/Using_SQLite_with_FireDAC#SQLite_Transactions.2C_Locking.2C_Threads_and_Cursors) finden Sie alle finden, die Sie benötigen. – Victoria

+0

Danke, ich habe es geschafft, die richtigen Parameter zu finden. Wenn Sie eine Antwort schreiben, werde ich es akzeptieren. Ansonsten beantworte ich die Frage selbst. – Stephane

+0

Geben Sie bitte eine Antwort ein. Ich bin jetzt ziemlich beschäftigt. – Victoria

Antwort

2

Dank Victoria gelang es mir, die richtigen Parameter zu finden.

Conn := TFDConnection.Create(nil); 
    try 
    Conn.DriverName := 'SQLite'; 
    Conn.LoginPrompt := false; 
    Conn.Params.clear; 
    Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb'); 
    Conn.Params.Add('DriverID=SQLite'); 
    Conn.Params.Add('SharedCache=False'); 
    Conn.Params.Add('LockingMode=Normal'); 
    Conn.Params.Add('Synchronous=Normal'); 
    Conn.UpdateOptions.LockWait := True; 
    Conn.Open(); 

Thanks again

Verwandte Themen