Sqlite Transaktionen unter Zeos

Die Sqlite Kopplung unter der Zeos Bibliothek verhält sich im Bereich der Datenbanktransaktionen nicht ganz wie erwartet:

Es wäre zu erwarten, dass eine manuelle Transaktionssteuerung immer Vorrang vor einer impliziten Steuerung hat – dem ist jedoch nicht so.

Ist in der TZConnection Komponente das Transaktionslevel „TransactIsolationLevel“ = tiNone und die Eigenschaft „AutoCommit“ = TRUE funktioniert jedes Post reibungslos, solange keine expliziten Transaktionen verwendet werden.

Bei expliziten Transaktionen über StartTransaction, Commit/Rollback werden schlicht keine Transaktionen angewendet: Die Performance der Datenbank ist dann entsprechend schlecht.
Damit Transaktionen wirksam werden, muss das Transaktionsisolationslevel z.B. auf tiReadCommitted gesetzt werden.

Ungeschickter Weise funktionieren in diesem Modus dann jedoch die impliziten Transaktionen nicht mehr: Die Änderungen der Datenmenge ohne expliziter Transaktion werden nicht mehr auf die DB zurückgeschrieben sondern nur noch im internen Puffer geändert. Eine Fehlermeldung erfolgt nicht. Das Problem wird erst beim nächsten Connect der Datenbank ersichtlich.

Um das Problem zu lösen muss das Property „TransactIsolationLevel“ vor dem Start einer Transaktion auf   tiReadCommitted gesetzt werden und nach einem Eintragen oder Zurückrollen der Änderungen wieder auf tiNone gesetzt werden. Zumindest kann diese Betriebsart in der Zeos Bibliothek umgeschaltet werden, ohne dass ein Disconnect/Connect erforderlich wäre.

Beispiel eines kompletten funktionstüchtigen Ablaufs mit und ohne expliziter Transaktionssteuerung:

(Einfügen von Datensätzen in eine Tabelle)

  ZConnection1.Connect;
  // 1.) einzelner datensatz - implizite transaktion
  ZConnection1.TransactIsolationLevel := tiNone;
  ZQuery1.Open;
  ZQuery1.Insert;
  ...
  // datensatz wird in die db geschrieben
  ZQuery1.Post;

  // 2.) viele datensaetze - bessere performance durch explizite transaktion
  ZConnection1.TransactIsolationLevel := tiReadCommitted;
  try
    ZConnection1.StartTransaction;
    try
      for i := 0 to 100 do
        begin
          ZQuery1.Insert;
          .. .
            ZQuery1.Post;
        end;
      ZConnection1.Commit;
      // viele daten wurden per transaktion in die db geschrieben
    except
      ZConnection1.Rollback;
      raise;
    end;
  finally
    ZConnection1.TransactIsolationLevel := tiNone;
  end;

 

Schreibe einen Kommentar